File Coverage

lib/IO/ExplicitHandle.xs
Criterion Covered Total %
statement 39 39 100.0
branch 55 106 51.8
condition n/a
subroutine n/a
pod n/a
total 94 145 64.8


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT 1
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #define Q_PERL_VERSION_DECIMAL(r,v,s) ((r)*1000000 + (v)*1000 + (s))
7             #define Q_PERL_DECIMAL_VERSION \
8             Q_PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
9             #define Q_PERL_VERSION_GE(r,v,s) \
10             (Q_PERL_DECIMAL_VERSION >= Q_PERL_VERSION_DECIMAL(r,v,s))
11             #define Q_PERL_VERSION_LT(r,v,s) \
12             (Q_PERL_DECIMAL_VERSION < Q_PERL_VERSION_DECIMAL(r,v,s))
13              
14             #if Q_PERL_VERSION_LT(5,7,2)
15             # undef dNOOP
16             # define dNOOP extern int Perl___notused_func(void)
17             #endif /* <5.7.2 */
18              
19             #if (Q_PERL_VERSION_GE(5,17,6) && Q_PERL_VERSION_LT(5,17,11)) || \
20             (Q_PERL_VERSION_GE(5,19,3) && Q_PERL_VERSION_LT(5,21,1))
21             PERL_STATIC_INLINE void suppress_unused_warning(void)
22             {
23             (void) S_croak_memory_wrap;
24             }
25             #endif /* (>=5.17.6 && <5.17.11) || (>=5.19.3 && <5.21.1) */
26              
27             #ifndef SVfARG
28             # define SVfARG(p) ((void *)(p))
29             #endif /* !SVfARG */
30              
31             #ifndef hv_fetchs
32             # define hv_fetchs(hv, keystr, lval) \
33             hv_fetch(hv, "" keystr "", sizeof(keystr)-1, lval)
34             #endif /* !hv_fetchs */
35              
36             #ifndef hv_deletes
37             # define hv_deletes(hv, keystr, flags) \
38             hv_delete(hv, "" keystr "", sizeof(keystr)-1, flags)
39             #endif /* !hv_deletes */
40              
41             #ifndef newSVpvs
42             # define newSVpvs(string) newSVpvn("" string "", sizeof(string)-1)
43             #endif /* !newSVpvs */
44              
45             #if Q_PERL_VERSION_GE(5,9,5)
46             # ifndef qerror
47             # define qerror(m) Perl_qerror(aTHX_ m)
48             # endif /* !qerror */
49             #else /* <5.9.5 */
50             # undef qerror
51             # define qerror(m) THX_qerror(aTHX_ m)
52             static void THX_qerror(pTHX_ SV *msg)
53             {
54             if(PL_in_eval)
55             sv_catsv(ERRSV, msg);
56             else if(PL_errors)
57             sv_catsv(PL_errors, msg);
58             else
59             Perl_warn(aTHX_ "%" SVf "", SVfARG(msg));
60             PL_error_count++;
61             }
62             #endif /* <5.9.5 */
63              
64             #ifndef GvNAMELEN_get
65             # define GvNAMELEN_get GvNAMELEN
66             #endif /* !GvNAMELEN_get */
67              
68             #ifndef GvNAME_get
69             # define GvNAME_get GvNAME
70             #endif /* !GvNAME_get */
71              
72             #if Q_PERL_VERSION_LT(5,9,3)
73             typedef OP *(*Perl_check_t)(pTHX_ OP *);
74             #endif /* <5.9.3 */
75              
76             #if Q_PERL_VERSION_LT(5,10,1)
77             typedef unsigned Optype;
78             #endif /* <5.10.1 */
79              
80             #if Q_PERL_VERSION_GE(5,7,3)
81             # define PERL_UNUSED_THX() NOOP
82             #else /* <5.7.3 */
83             # define PERL_UNUSED_THX() ((void)(aTHX+0))
84             #endif /* <5.7.3 */
85              
86             #ifndef wrap_op_checker
87             # define wrap_op_checker(c,n,o) THX_wrap_op_checker(aTHX_ c,n,o)
88             static void THX_wrap_op_checker(pTHX_ Optype opcode,
89             Perl_check_t new_checker, Perl_check_t *old_checker_p)
90             {
91             PERL_UNUSED_THX();
92             if(*old_checker_p) return;
93             OP_REFCNT_LOCK;
94             if(!*old_checker_p) {
95             *old_checker_p = PL_check[opcode];
96             PL_check[opcode] = new_checker;
97             }
98             OP_REFCNT_UNLOCK;
99             }
100             #endif /* !wrap_op_checker */
101              
102             #define Q_HAVE_SAY Q_PERL_VERSION_GE(5,9,3)
103              
104             #define STRICT_HINT_KEY "IO::ExplicitHandle/strict"
105              
106             #define in_strictexplicithandle() THX_in_strictexplicithandle(aTHX)
107 549           static bool THX_in_strictexplicithandle(pTHX)
108             {
109 549           SV **svp = hv_fetchs(GvHV(PL_hintgv), STRICT_HINT_KEY, 0);
110 549 100         return svp && SvTRUE(*svp);
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
111             }
112              
113             #define qerror_unspec_handle_op(c) THX_qerror_unspec_handle_op(aTHX_ c)
114 20           static void THX_qerror_unspec_handle_op(pTHX_ Optype opcode)
115             {
116 20           qerror(mess("Unspecified I/O handle in %s", PL_op_desc[opcode]));
117 20           }
118              
119             #define EXPLICITHANDLE_OP_CHECKER(OPNAME, opname, is_bad) \
120             static Perl_check_t THX_nxck_##opname; \
121             static OP *THX_myck_##opname(pTHX_ OP *op) \
122             { \
123             if(!in_strictexplicithandle()) \
124             return THX_nxck_##opname(aTHX_ op); \
125             op = THX_nxck_##opname(aTHX_ op); \
126             if(op->op_type == OP_##OPNAME && (is_bad)) \
127             qerror_unspec_handle_op(OP_##OPNAME); \
128             return op; \
129             }
130              
131 96 100         EXPLICITHANDLE_OP_CHECKER(PRINT, print, !(op->op_flags & OPf_STACKED))
    50          
    100          
132              
133 8 50         EXPLICITHANDLE_OP_CHECKER(PRTF, prtf, !(op->op_flags & OPf_STACKED))
    50          
    100          
134              
135             #if Q_HAVE_SAY
136 8 50         EXPLICITHANDLE_OP_CHECKER(SAY, say, !(op->op_flags & OPf_STACKED))
    50          
    100          
137             #endif /* Q_HAVE_SAY */
138              
139 8 50         EXPLICITHANDLE_OP_CHECKER(CLOSE, close, !(op->op_private & 15))
    50          
    100          
140              
141 12 50         EXPLICITHANDLE_OP_CHECKER(ENTERWRITE, enterwrite, !(op->op_private & 15))
    50          
    100          
142              
143 8 50         EXPLICITHANDLE_OP_CHECKER(EOF, eof,
    50          
    100          
    100          
144             !(op->op_private & 15) && !(op->op_flags & OPf_SPECIAL))
145              
146 8 50         EXPLICITHANDLE_OP_CHECKER(TELL, tell, !(op->op_private & 15))
    50          
    100          
147              
148             static Perl_check_t THX_nxck_rv2sv;
149 475           static OP *THX_myck_rv2sv(pTHX_ OP *op)
150             {
151             OP *rvop;
152             GV *gv;
153 475 100         if(!in_strictexplicithandle()) return THX_nxck_rv2sv(aTHX_ op);
154 16           op = THX_nxck_rv2sv(aTHX_ op);
155 16 50         if(op->op_type == OP_RV2SV && (op->op_flags & OPf_KIDS) &&
    50          
    50          
156 16 50         (rvop = cUNOPx(op)->op_first) &&
157 16 50         (rvop->op_type == OP_GV) && (gv = cGVOPx_gv(rvop)) &&
    50          
158 16 50         isGV((SV*)gv) && GvNAMELEN_get(gv) == 1) {
159 16           char nc = *GvNAME_get(gv);
160 16 100         switch(nc) {
161             case '|':
162             case '^':
163             case '~':
164             case '=':
165             case '-':
166             case '%':
167             case '.':
168 14           qerror(mess("Unspecified I/O handle in $%c",
169             nc));
170             }
171             }
172             return op;
173             }
174              
175             MODULE = IO::ExplicitHandle PACKAGE = IO::ExplicitHandle
176              
177             PROTOTYPES: DISABLE
178              
179             BOOT:
180              
181 2           wrap_op_checker(OP_PRINT, THX_myck_print, &THX_nxck_print);
182 2           wrap_op_checker(OP_PRTF, THX_myck_prtf, &THX_nxck_prtf);
183             #if Q_HAVE_SAY
184 2           wrap_op_checker(OP_SAY, THX_myck_say, &THX_nxck_say);
185             #endif /* Q_HAVE_SAY */
186 2           wrap_op_checker(OP_CLOSE, THX_myck_close, &THX_nxck_close);
187 2           wrap_op_checker(OP_ENTERWRITE, THX_myck_enterwrite,
188             &THX_nxck_enterwrite);
189 2           wrap_op_checker(OP_EOF, THX_myck_eof, &THX_nxck_eof);
190 2           wrap_op_checker(OP_TELL, THX_myck_tell, &THX_nxck_tell);
191 2           wrap_op_checker(OP_RV2SV, THX_myck_rv2sv, &THX_nxck_rv2sv);
192              
193             void
194             import(SV *classname)
195             PREINIT:
196             SV *val;
197             CODE:
198             PERL_UNUSED_VAR(classname);
199 53           PL_hints |= HINT_LOCALIZE_HH;
200 53           gv_HVadd(PL_hintgv);
201 53           val = newSVsv(&PL_sv_yes);
202 53 50         if(hv_store_ent(GvHV(PL_hintgv), sv_2mortal(newSVpvs(STRICT_HINT_KEY)),
203             val, 0)) {
204 53 50         SvSETMAGIC(val);
205             } else {
206             SvREFCNT_dec(val);
207             }
208              
209             void
210             unimport(SV *classname)
211             CODE:
212             PERL_UNUSED_VAR(classname);
213 4           PL_hints |= HINT_LOCALIZE_HH;
214 4           gv_HVadd(PL_hintgv);
215 4           (void) hv_deletes(GvHV(PL_hintgv), STRICT_HINT_KEY, G_DISCARD);