This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
relax range checking if they ask for it (from John L. Allen
[perl5.git] / xsutils.c
1 #include "EXTERN.h"
2 #define PERL_IN_XSUTILS_C
3 #include "perl.h"
4
5 /*
6  * Contributed by Spider Boardman (spider.boardman@orb.nashua.nh.us).
7  */
8
9 /* package attributes; */
10 void XS_attributes__warn_reserved(pTHXo_ CV *cv);
11 void XS_attributes_reftype(pTHXo_ CV *cv);
12 void XS_attributes__modify_attrs(pTHXo_ CV *cv);
13 void XS_attributes__guess_stash(pTHXo_ CV *cv);
14 void XS_attributes__fetch_attrs(pTHXo_ CV *cv);
15 void XS_attributes_bootstrap(pTHXo_ CV *cv);
16
17
18 /*
19  * Note that only ${pkg}::bootstrap definitions should go here.
20  * This helps keep down the start-up time, which is especially
21  * relevant for users who don't invoke any features which are
22  * (partially) implemented here.
23  *
24  * The various bootstrap definitions can take care of doing
25  * package-specific newXS() calls.  Since the layout of the
26  * bundled lib/*.pm files is in a version-specific directory,
27  * version checks in these bootstrap calls are optional.
28  */
29
30 void
31 Perl_boot_core_xsutils(pTHX)
32 {
33     char *file = __FILE__;
34
35     newXS("attributes::bootstrap",      XS_attributes_bootstrap,        file);
36 }
37
38 #ifdef PERL_OBJECT
39 #define NO_XSLOCKS
40 #endif  /* PERL_OBJECT */
41
42 #include "XSUB.h"
43
44 static int
45 modify_SV_attributes(pTHXo_ SV *sv, SV **retlist, SV **attrlist, int numattrs)
46 {
47     SV *attr;
48     char *name;
49     STRLEN len;
50     bool negated;
51     int nret;
52
53     for (nret = 0 ; numattrs && (attr = *attrlist++); numattrs--) {
54         name = SvPV(attr, len);
55         if (negated = (*name == '-')) {
56             name++;
57             len--;
58         }
59         switch (SvTYPE(sv)) {
60         case SVt_PVCV:
61             switch ((int)len) {
62             case 6:
63                 switch (*name) {
64                 case 'l':
65 #ifdef CVf_LVALUE
66                     if (strEQ(name, "lvalue")) {
67                         if (negated)
68                             CvFLAGS((CV*)sv) &= ~CVf_LVALUE;
69                         else
70                             CvFLAGS((CV*)sv) |= CVf_LVALUE;
71                         continue;
72                     }
73 #endif /* defined CVf_LVALUE */
74                     if (strEQ(name, "locked")) {
75                         if (negated)
76                             CvFLAGS((CV*)sv) &= ~CVf_LOCKED;
77                         else
78                             CvFLAGS((CV*)sv) |= CVf_LOCKED;
79                         continue;
80                     }
81                     break;
82                 case 'm':
83                     if (strEQ(name, "method")) {
84                         if (negated)
85                             CvFLAGS((CV*)sv) &= ~CVf_METHOD;
86                         else
87                             CvFLAGS((CV*)sv) |= CVf_METHOD;
88                         continue;
89                     }
90                     break;
91                 }
92                 break;
93             }
94             break;
95         default:
96             /* nothing, yet */
97             break;
98         }
99         /* anything recognized had a 'continue' above */
100         *retlist++ = attr;
101         nret++;
102     }
103
104     return nret;
105 }
106
107
108
109 /* package attributes; */
110
111 XS(XS_attributes_bootstrap)
112 {
113     dXSARGS;
114     char *file = __FILE__;
115
116     newXSproto("attributes::_warn_reserved", XS_attributes__warn_reserved, file, "");
117     newXS("attributes::_modify_attrs",  XS_attributes__modify_attrs,    file);
118     newXSproto("attributes::_guess_stash", XS_attributes__guess_stash, file, "$");
119     newXSproto("attributes::_fetch_attrs", XS_attributes__fetch_attrs, file, "$");
120     newXSproto("attributes::reftype",   XS_attributes_reftype,  file, "$");
121
122     XSRETURN(0);
123 }
124
125 XS(XS_attributes__modify_attrs)
126 {
127     dXSARGS;
128     SV *rv, *sv;
129
130     if (items < 1) {
131 usage:
132         Perl_croak(aTHX_
133                    "Usage: attributes::_modify_attrs $reference, @attributes");
134     }
135
136     rv = ST(0);
137     if (!(SvOK(rv) && SvROK(rv)))
138         goto usage;
139     sv = SvRV(rv);
140     if (items > 1)
141         XSRETURN(modify_SV_attributes(aTHXo_ sv, &ST(0), &ST(1), items-1));
142
143     XSRETURN(0);
144 }
145
146 XS(XS_attributes__fetch_attrs)
147 {
148     dXSARGS;
149     SV *rv, *sv;
150     cv_flags_t cvflags;
151
152     if (items != 1) {
153 usage:
154         Perl_croak(aTHX_
155                    "Usage: attributes::_fetch_attrs $reference");
156     }
157
158     rv = ST(0);
159     SP -= items;
160     if (!(SvOK(rv) && SvROK(rv)))
161         goto usage;
162     sv = SvRV(rv);
163
164     switch (SvTYPE(sv)) {
165     case SVt_PVCV:
166         cvflags = CvFLAGS((CV*)sv);
167         if (cvflags & CVf_LOCKED)
168             XPUSHs(sv_2mortal(newSVpvn("locked", 6)));
169 #ifdef CVf_LVALUE
170         if (cvflags & CVf_LVALUE)
171             XPUSHs(sv_2mortal(newSVpvn("lvalue", 6)));
172 #endif
173         if (cvflags & CVf_METHOD)
174             XPUSHs(sv_2mortal(newSVpvn("method", 6)));
175         break;
176     default:
177         break;
178     }
179
180     PUTBACK;
181 }
182
183 XS(XS_attributes__guess_stash)
184 {
185     dXSARGS;
186     SV *rv, *sv;
187 #ifdef dXSTARGET
188     dXSTARGET;
189 #else
190     SV * TARG = sv_newmortal();
191 #endif
192
193     if (items != 1) {
194 usage:
195         Perl_croak(aTHX_
196                    "Usage: attributes::_guess_stash $reference");
197     }
198
199     rv = ST(0);
200     ST(0) = TARG;
201     if (!(SvOK(rv) && SvROK(rv)))
202         goto usage;
203     sv = SvRV(rv);
204
205     if (SvOBJECT(sv))
206         sv_setpv(TARG, HvNAME(SvSTASH(sv)));
207 #if 0   /* this was probably a bad idea */
208     else if (SvPADMY(sv))
209         sv_setsv(TARG, &PL_sv_no);      /* unblessed lexical */
210 #endif
211     else {
212         HV *stash = Nullhv;
213         switch (SvTYPE(sv)) {
214         case SVt_PVCV:
215             if (CvGV(sv) && isGV(CvGV(sv)) && GvSTASH(CvGV(sv)) &&
216                             HvNAME(GvSTASH(CvGV(sv))))
217                 stash = GvSTASH(CvGV(sv));
218             else if (/* !CvANON(sv) && */ CvSTASH(sv) && HvNAME(CvSTASH(sv)))
219                 stash = CvSTASH(sv);
220             break;
221         case SVt_PVMG:
222             if (!(SvFAKE(sv) && SvTIED_mg(sv, '*')))
223                 break;
224             /*FALLTHROUGH*/
225         case SVt_PVGV:
226             if (GvGP(sv) && GvESTASH((GV*)sv) && HvNAME(GvESTASH((GV*)sv)))
227                 stash = GvESTASH((GV*)sv);
228             break;
229         default:
230             break;
231         }
232         if (stash)
233             sv_setpv(TARG, HvNAME(stash));
234     }
235
236 #ifdef dXSTARGET
237     SvSETMAGIC(TARG);
238 #endif
239     XSRETURN(1);
240 }
241
242 XS(XS_attributes_reftype)
243 {
244     dXSARGS;
245     SV *rv, *sv;
246 #ifdef dXSTARGET
247     dXSTARGET;
248 #else
249     SV * TARG = sv_newmortal();
250 #endif
251
252     if (items != 1) {
253 usage:
254         Perl_croak(aTHX_
255                    "Usage: attributes::reftype $reference");
256     }
257
258     rv = ST(0);
259     ST(0) = TARG;
260     if (!SvOK(rv)) {
261         ST(0) = &PL_sv_no;
262         XSRETURN(1);
263     }
264     if (!SvROK(rv))
265         goto usage;
266     sv = SvRV(rv);
267     sv_setpv(TARG, sv_reftype(sv, 0));
268 #ifdef dXSTARGET
269     SvSETMAGIC(TARG);
270 #endif
271
272     XSRETURN(1);
273 }
274
275 XS(XS_attributes__warn_reserved)
276 {
277     dXSARGS;
278     SV *rv, *sv;
279 #ifdef dXSTARGET
280     dXSTARGET;
281 #else
282     SV * TARG = sv_newmortal();
283 #endif
284
285     if (items != 0) {
286         Perl_croak(aTHX_
287                    "Usage: attributes::_warn_reserved ()");
288     }
289
290     EXTEND(SP,1);
291     ST(0) = TARG;
292     sv_setiv(TARG, ckWARN(WARN_RESERVED) != 0);
293 #ifdef dXSTARGET
294     SvSETMAGIC(TARG);
295 #endif
296
297     XSRETURN(1);
298 }
299