xref: /openbsd/gnu/usr.bin/perl/universal.c (revision cecf84d4)
1 /*    universal.c
2  *
3  *    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4  *    2005, 2006, 2007, 2008 by Larry Wall and others
5  *
6  *    You may distribute under the terms of either the GNU General Public
7  *    License or the Artistic License, as specified in the README file.
8  *
9  */
10 
11 /*
12  * '"The roots of those mountains must be roots indeed; there must be
13  *   great secrets buried there which have not been discovered since the
14  *   beginning."'                   --Gandalf, relating Gollum's history
15  *
16  *     [p.54 of _The Lord of the Rings_, I/ii: "The Shadow of the Past"]
17  */
18 
19 /* This file contains the code that implements the functions in Perl's
20  * UNIVERSAL package, such as UNIVERSAL->can().
21  *
22  * It is also used to store XS functions that need to be present in
23  * miniperl for a lack of a better place to put them. It might be
24  * clever to move them to separate XS files which would then be pulled
25  * in by some to-be-written build process.
26  */
27 
28 #include "EXTERN.h"
29 #define PERL_IN_UNIVERSAL_C
30 #include "perl.h"
31 
32 #if defined(USE_PERLIO)
33 #include "perliol.h" /* For the PERLIO_F_XXX */
34 #endif
35 
36 /*
37  * Contributed by Graham Barr  <Graham.Barr@tiuk.ti.com>
38  * The main guts of traverse_isa was actually copied from gv_fetchmeth
39  */
40 
41 STATIC bool
42 S_isa_lookup(pTHX_ HV *stash, const char * const name, STRLEN len, U32 flags)
43 {
44     dVAR;
45     const struct mro_meta *const meta = HvMROMETA(stash);
46     HV *isa = meta->isa;
47     const HV *our_stash;
48 
49     PERL_ARGS_ASSERT_ISA_LOOKUP;
50 
51     if (!isa) {
52 	(void)mro_get_linear_isa(stash);
53 	isa = meta->isa;
54     }
55 
56     if (hv_common(isa, NULL, name, len, ( flags & SVf_UTF8 ? HVhek_UTF8 : 0),
57 		  HV_FETCH_ISEXISTS, NULL, 0)) {
58 	/* Direct name lookup worked.  */
59 	return TRUE;
60     }
61 
62     /* A stash/class can go by many names (ie. User == main::User), so
63        we use the HvENAME in the stash itself, which is canonical, falling
64        back to HvNAME if necessary.  */
65     our_stash = gv_stashpvn(name, len, flags);
66 
67     if (our_stash) {
68 	HEK *canon_name = HvENAME_HEK(our_stash);
69 	if (!canon_name) canon_name = HvNAME_HEK(our_stash);
70 
71 	if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name),
72 		      HEK_FLAGS(canon_name),
73 		      HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) {
74 	    return TRUE;
75 	}
76     }
77 
78     return FALSE;
79 }
80 
81 /*
82 =head1 SV Manipulation Functions
83 
84 =for apidoc sv_derived_from_pvn
85 
86 Returns a boolean indicating whether the SV is derived from the specified class
87 I<at the C level>.  To check derivation at the Perl level, call C<isa()> as a
88 normal Perl method.
89 
90 Currently, the only significant value for C<flags> is SVf_UTF8.
91 
92 =cut
93 
94 =for apidoc sv_derived_from_sv
95 
96 Exactly like L</sv_derived_from_pvn>, but takes the name string in the form
97 of an SV instead of a string/length pair.
98 
99 =cut
100 
101 */
102 
103 bool
104 Perl_sv_derived_from_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
105 {
106     char *namepv;
107     STRLEN namelen;
108     PERL_ARGS_ASSERT_SV_DERIVED_FROM_SV;
109     namepv = SvPV(namesv, namelen);
110     if (SvUTF8(namesv))
111        flags |= SVf_UTF8;
112     return sv_derived_from_pvn(sv, namepv, namelen, flags);
113 }
114 
115 /*
116 =for apidoc sv_derived_from
117 
118 Exactly like L</sv_derived_from_pv>, but doesn't take a C<flags> parameter.
119 
120 =cut
121 */
122 
123 bool
124 Perl_sv_derived_from(pTHX_ SV *sv, const char *const name)
125 {
126     PERL_ARGS_ASSERT_SV_DERIVED_FROM;
127     return sv_derived_from_pvn(sv, name, strlen(name), 0);
128 }
129 
130 /*
131 =for apidoc sv_derived_from_pv
132 
133 Exactly like L</sv_derived_from_pvn>, but takes a nul-terminated string
134 instead of a string/length pair.
135 
136 =cut
137 */
138 
139 
140 bool
141 Perl_sv_derived_from_pv(pTHX_ SV *sv, const char *const name, U32 flags)
142 {
143     PERL_ARGS_ASSERT_SV_DERIVED_FROM_PV;
144     return sv_derived_from_pvn(sv, name, strlen(name), flags);
145 }
146 
147 bool
148 Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags)
149 {
150     dVAR;
151     HV *stash;
152 
153     PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN;
154 
155     SvGETMAGIC(sv);
156 
157     if (SvROK(sv)) {
158 	const char *type;
159         sv = SvRV(sv);
160         type = sv_reftype(sv,0);
161 	if (type && strEQ(type,name))
162 	    return TRUE;
163         if (!SvOBJECT(sv))
164             return FALSE;
165 	stash = SvSTASH(sv);
166     }
167     else {
168         stash = gv_stashsv(sv, 0);
169     }
170 
171     if (stash && isa_lookup(stash, name, len, flags))
172         return TRUE;
173 
174     stash = gv_stashpvs("UNIVERSAL", 0);
175     return stash && isa_lookup(stash, name, len, flags);
176 }
177 
178 /*
179 =for apidoc sv_does_sv
180 
181 Returns a boolean indicating whether the SV performs a specific, named role.
182 The SV can be a Perl object or the name of a Perl class.
183 
184 =cut
185 */
186 
187 #include "XSUB.h"
188 
189 bool
190 Perl_sv_does_sv(pTHX_ SV *sv, SV *namesv, U32 flags)
191 {
192     SV *classname;
193     bool does_it;
194     SV *methodname;
195     dSP;
196 
197     PERL_ARGS_ASSERT_SV_DOES_SV;
198     PERL_UNUSED_ARG(flags);
199 
200     ENTER;
201     SAVETMPS;
202 
203     SvGETMAGIC(sv);
204 
205     if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv)))) {
206 	LEAVE;
207 	return FALSE;
208     }
209 
210     if (sv_isobject(sv)) {
211 	classname = sv_ref(NULL,SvRV(sv),TRUE);
212     } else {
213 	classname = sv;
214     }
215 
216     if (sv_eq(classname, namesv)) {
217 	LEAVE;
218 	return TRUE;
219     }
220 
221     PUSHMARK(SP);
222     EXTEND(SP, 2);
223     PUSHs(sv);
224     PUSHs(namesv);
225     PUTBACK;
226 
227     methodname = newSVpvs_flags("isa", SVs_TEMP);
228     /* ugly hack: use the SvSCREAM flag so S_method_common
229      * can figure out we're calling DOES() and not isa(),
230      * and report eventual errors correctly. --rgs */
231     SvSCREAM_on(methodname);
232     call_sv(methodname, G_SCALAR | G_METHOD);
233     SPAGAIN;
234 
235     does_it = SvTRUE( TOPs );
236     FREETMPS;
237     LEAVE;
238 
239     return does_it;
240 }
241 
242 /*
243 =for apidoc sv_does
244 
245 Like L</sv_does_pv>, but doesn't take a C<flags> parameter.
246 
247 =cut
248 */
249 
250 bool
251 Perl_sv_does(pTHX_ SV *sv, const char *const name)
252 {
253     PERL_ARGS_ASSERT_SV_DOES;
254     return sv_does_sv(sv, newSVpvn_flags(name, strlen(name), SVs_TEMP), 0);
255 }
256 
257 /*
258 =for apidoc sv_does_pv
259 
260 Like L</sv_does_sv>, but takes a nul-terminated string instead of an SV.
261 
262 =cut
263 */
264 
265 
266 bool
267 Perl_sv_does_pv(pTHX_ SV *sv, const char *const name, U32 flags)
268 {
269     PERL_ARGS_ASSERT_SV_DOES_PV;
270     return sv_does_sv(sv, newSVpvn_flags(name, strlen(name), SVs_TEMP | flags), flags);
271 }
272 
273 /*
274 =for apidoc sv_does_pvn
275 
276 Like L</sv_does_sv>, but takes a string/length pair instead of an SV.
277 
278 =cut
279 */
280 
281 bool
282 Perl_sv_does_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags)
283 {
284     PERL_ARGS_ASSERT_SV_DOES_PVN;
285 
286     return sv_does_sv(sv, newSVpvn_flags(name, len, flags | SVs_TEMP), flags);
287 }
288 
289 /*
290 =for apidoc croak_xs_usage
291 
292 A specialised variant of C<croak()> for emitting the usage message for xsubs
293 
294     croak_xs_usage(cv, "eee_yow");
295 
296 works out the package name and subroutine name from C<cv>, and then calls
297 C<croak()>.  Hence if C<cv> is C<&ouch::awk>, it would call C<croak> as:
298 
299     Perl_croak(aTHX_ "Usage: %"SVf"::%"SVf"(%s)", "ouch" "awk", "eee_yow");
300 
301 =cut
302 */
303 
304 void
305 Perl_croak_xs_usage(const CV *const cv, const char *const params)
306 {
307     const GV *const gv = CvGV(cv);
308 
309     PERL_ARGS_ASSERT_CROAK_XS_USAGE;
310 
311     if (gv) {
312 	const HV *const stash = GvSTASH(gv);
313 
314 	if (HvNAME_get(stash))
315 	    /* diag_listed_as: SKIPME */
316 	    Perl_croak_nocontext("Usage: %"HEKf"::%"HEKf"(%s)",
317                                 HEKfARG(HvNAME_HEK(stash)),
318                                 HEKfARG(GvNAME_HEK(gv)),
319                                 params);
320 	else
321 	    /* diag_listed_as: SKIPME */
322 	    Perl_croak_nocontext("Usage: %"HEKf"(%s)",
323                                 HEKfARG(GvNAME_HEK(gv)), params);
324     } else {
325 	/* Pants. I don't think that it should be possible to get here. */
326 	/* diag_listed_as: SKIPME */
327 	Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
328     }
329 }
330 
331 XS(XS_UNIVERSAL_isa); /* prototype to pass -Wmissing-prototypes */
332 XS(XS_UNIVERSAL_isa)
333 {
334     dVAR;
335     dXSARGS;
336 
337     if (items != 2)
338 	croak_xs_usage(cv, "reference, kind");
339     else {
340 	SV * const sv = ST(0);
341 
342 	SvGETMAGIC(sv);
343 
344 	if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))))
345 	    XSRETURN_UNDEF;
346 
347 	ST(0) = boolSV(sv_derived_from_sv(sv, ST(1), 0));
348 	XSRETURN(1);
349     }
350 }
351 
352 XS(XS_UNIVERSAL_can); /* prototype to pass -Wmissing-prototypes */
353 XS(XS_UNIVERSAL_can)
354 {
355     dVAR;
356     dXSARGS;
357     SV   *sv;
358     SV   *rv;
359     HV   *pkg = NULL;
360     GV   *iogv;
361 
362     if (items != 2)
363 	croak_xs_usage(cv, "object-ref, method");
364 
365     sv = ST(0);
366 
367     SvGETMAGIC(sv);
368 
369     /* Reject undef and empty string.  Note that the string form takes
370        precedence here over the numeric form, as (!1)->foo treats the
371        invocant as the empty string, though it is a dualvar. */
372     if (!SvOK(sv) || (SvPOK(sv) && !SvCUR(sv)))
373 	XSRETURN_UNDEF;
374 
375     rv = &PL_sv_undef;
376 
377     if (SvROK(sv)) {
378         sv = MUTABLE_SV(SvRV(sv));
379         if (SvOBJECT(sv))
380             pkg = SvSTASH(sv);
381         else if (isGV_with_GP(sv) && GvIO(sv))
382 	    pkg = SvSTASH(GvIO(sv));
383     }
384     else if (isGV_with_GP(sv) && GvIO(sv))
385         pkg = SvSTASH(GvIO(sv));
386     else if ((iogv = gv_fetchsv_nomg(sv, 0, SVt_PVIO)) && GvIO(iogv))
387         pkg = SvSTASH(GvIO(iogv));
388     else {
389         pkg = gv_stashsv(sv, 0);
390         if (!pkg)
391             pkg = gv_stashpv("UNIVERSAL", 0);
392     }
393 
394     if (pkg) {
395 	GV * const gv = gv_fetchmethod_sv_flags(pkg, ST(1), 0);
396         if (gv && isGV(gv))
397 	    rv = sv_2mortal(newRV(MUTABLE_SV(GvCV(gv))));
398     }
399 
400     ST(0) = rv;
401     XSRETURN(1);
402 }
403 
404 XS(XS_UNIVERSAL_DOES); /* prototype to pass -Wmissing-prototypes */
405 XS(XS_UNIVERSAL_DOES)
406 {
407     dVAR;
408     dXSARGS;
409     PERL_UNUSED_ARG(cv);
410 
411     if (items != 2)
412 	Perl_croak(aTHX_ "Usage: invocant->DOES(kind)");
413     else {
414 	SV * const sv = ST(0);
415 	if (sv_does_sv( sv, ST(1), 0 ))
416 	    XSRETURN_YES;
417 
418 	XSRETURN_NO;
419     }
420 }
421 
422 XS(XS_utf8_is_utf8); /* prototype to pass -Wmissing-prototypes */
423 XS(XS_utf8_is_utf8)
424 {
425      dVAR;
426      dXSARGS;
427      if (items != 1)
428 	 croak_xs_usage(cv, "sv");
429      else {
430 	SV * const sv = ST(0);
431 	SvGETMAGIC(sv);
432 	    if (SvUTF8(sv))
433 		XSRETURN_YES;
434 	    else
435 		XSRETURN_NO;
436      }
437      XSRETURN_EMPTY;
438 }
439 
440 XS(XS_utf8_valid); /* prototype to pass -Wmissing-prototypes */
441 XS(XS_utf8_valid)
442 {
443      dVAR;
444      dXSARGS;
445      if (items != 1)
446 	 croak_xs_usage(cv, "sv");
447     else {
448 	SV * const sv = ST(0);
449 	STRLEN len;
450 	const char * const s = SvPV_const(sv,len);
451 	if (!SvUTF8(sv) || is_utf8_string((const U8*)s,len))
452 	    XSRETURN_YES;
453 	else
454 	    XSRETURN_NO;
455     }
456      XSRETURN_EMPTY;
457 }
458 
459 XS(XS_utf8_encode); /* prototype to pass -Wmissing-prototypes */
460 XS(XS_utf8_encode)
461 {
462     dVAR;
463     dXSARGS;
464     if (items != 1)
465 	croak_xs_usage(cv, "sv");
466     sv_utf8_encode(ST(0));
467     SvSETMAGIC(ST(0));
468     XSRETURN_EMPTY;
469 }
470 
471 XS(XS_utf8_decode); /* prototype to pass -Wmissing-prototypes */
472 XS(XS_utf8_decode)
473 {
474     dVAR;
475     dXSARGS;
476     if (items != 1)
477 	croak_xs_usage(cv, "sv");
478     else {
479 	SV * const sv = ST(0);
480 	bool RETVAL;
481 	SvPV_force_nolen(sv);
482 	RETVAL = sv_utf8_decode(sv);
483 	SvSETMAGIC(sv);
484 	ST(0) = boolSV(RETVAL);
485     }
486     XSRETURN(1);
487 }
488 
489 XS(XS_utf8_upgrade); /* prototype to pass -Wmissing-prototypes */
490 XS(XS_utf8_upgrade)
491 {
492     dVAR;
493     dXSARGS;
494     if (items != 1)
495 	croak_xs_usage(cv, "sv");
496     else {
497 	SV * const sv = ST(0);
498 	STRLEN	RETVAL;
499 	dXSTARG;
500 
501 	RETVAL = sv_utf8_upgrade(sv);
502 	XSprePUSH; PUSHi((IV)RETVAL);
503     }
504     XSRETURN(1);
505 }
506 
507 XS(XS_utf8_downgrade); /* prototype to pass -Wmissing-prototypes */
508 XS(XS_utf8_downgrade)
509 {
510     dVAR;
511     dXSARGS;
512     if (items < 1 || items > 2)
513 	croak_xs_usage(cv, "sv, failok=0");
514     else {
515 	SV * const sv = ST(0);
516         const bool failok = (items < 2) ? 0 : (int)SvIV(ST(1));
517         const bool RETVAL = sv_utf8_downgrade(sv, failok);
518 
519 	ST(0) = boolSV(RETVAL);
520     }
521     XSRETURN(1);
522 }
523 
524 XS(XS_utf8_native_to_unicode); /* prototype to pass -Wmissing-prototypes */
525 XS(XS_utf8_native_to_unicode)
526 {
527  dVAR;
528  dXSARGS;
529  const UV uv = SvUV(ST(0));
530 
531  if (items > 1)
532      croak_xs_usage(cv, "sv");
533 
534  ST(0) = sv_2mortal(newSViv(NATIVE_TO_UNI(uv)));
535  XSRETURN(1);
536 }
537 
538 XS(XS_utf8_unicode_to_native); /* prototype to pass -Wmissing-prototypes */
539 XS(XS_utf8_unicode_to_native)
540 {
541  dVAR;
542  dXSARGS;
543  const UV uv = SvUV(ST(0));
544 
545  if (items > 1)
546      croak_xs_usage(cv, "sv");
547 
548  ST(0) = sv_2mortal(newSViv(UNI_TO_NATIVE(uv)));
549  XSRETURN(1);
550 }
551 
552 XS(XS_Internals_SvREADONLY); /* prototype to pass -Wmissing-prototypes */
553 XS(XS_Internals_SvREADONLY)	/* This is dangerous stuff. */
554 {
555     dVAR;
556     dXSARGS;
557     SV * const svz = ST(0);
558     SV * sv;
559     PERL_UNUSED_ARG(cv);
560 
561     /* [perl #77776] - called as &foo() not foo() */
562     if (!SvROK(svz))
563         croak_xs_usage(cv, "SCALAR[, ON]");
564 
565     sv = SvRV(svz);
566 
567     if (items == 1) {
568 	 if (SvREADONLY(sv))
569 	     XSRETURN_YES;
570 	 else
571 	     XSRETURN_NO;
572     }
573     else if (items == 2) {
574 	if (SvTRUE(ST(1))) {
575 #ifdef PERL_OLD_COPY_ON_WRITE
576 	    if (SvIsCOW(sv)) sv_force_normal(sv);
577 #endif
578 	    SvREADONLY_on(sv);
579 	    XSRETURN_YES;
580 	}
581 	else {
582 	    /* I hope you really know what you are doing. */
583 	    SvREADONLY_off(sv);
584 	    XSRETURN_NO;
585 	}
586     }
587     XSRETURN_UNDEF; /* Can't happen. */
588 }
589 
590 XS(XS_constant__make_const); /* prototype to pass -Wmissing-prototypes */
591 XS(XS_constant__make_const)	/* This is dangerous stuff. */
592 {
593     dVAR;
594     dXSARGS;
595     SV * const svz = ST(0);
596     SV * sv;
597     PERL_UNUSED_ARG(cv);
598 
599     /* [perl #77776] - called as &foo() not foo() */
600     if (!SvROK(svz) || items != 1)
601         croak_xs_usage(cv, "SCALAR");
602 
603     sv = SvRV(svz);
604 
605 #ifdef PERL_OLD_COPY_ON_WRITE
606     if (SvIsCOW(sv)) sv_force_normal(sv);
607 #endif
608     SvREADONLY_on(sv);
609     if (SvTYPE(sv) == SVt_PVAV && AvFILLp(sv) != -1) {
610 	/* for constant.pm; nobody else should be calling this
611 	   on arrays anyway. */
612 	SV **svp;
613 	for (svp = AvARRAY(sv) + AvFILLp(sv)
614 	   ; svp >= AvARRAY(sv)
615 	   ; --svp)
616 	    if (*svp) SvPADTMP_on(*svp);
617     }
618     XSRETURN(0);
619 }
620 
621 XS(XS_Internals_SvREFCNT); /* prototype to pass -Wmissing-prototypes */
622 XS(XS_Internals_SvREFCNT)	/* This is dangerous stuff. */
623 {
624     dVAR;
625     dXSARGS;
626     SV * const svz = ST(0);
627     SV * sv;
628     U32 refcnt;
629     PERL_UNUSED_ARG(cv);
630 
631     /* [perl #77776] - called as &foo() not foo() */
632     if ((items != 1 && items != 2) || !SvROK(svz))
633         croak_xs_usage(cv, "SCALAR[, REFCOUNT]");
634 
635     sv = SvRV(svz);
636 
637          /* I hope you really know what you are doing. */
638     /* idea is for SvREFCNT(sv) to be accessed only once */
639     refcnt = items == 2 ?
640                 /* we free one ref on exit */
641                 (SvREFCNT(sv) = SvUV(ST(1)) + 1)
642                 : SvREFCNT(sv);
643     XSRETURN_UV(refcnt - 1); /* Minus the ref created for us. */
644 
645 }
646 
647 XS(XS_Internals_hv_clear_placehold); /* prototype to pass -Wmissing-prototypes */
648 XS(XS_Internals_hv_clear_placehold)
649 {
650     dVAR;
651     dXSARGS;
652 
653     if (items != 1 || !SvROK(ST(0)))
654 	croak_xs_usage(cv, "hv");
655     else {
656 	HV * const hv = MUTABLE_HV(SvRV(ST(0)));
657 	hv_clear_placeholders(hv);
658 	XSRETURN(0);
659     }
660 }
661 
662 XS(XS_PerlIO_get_layers); /* prototype to pass -Wmissing-prototypes */
663 XS(XS_PerlIO_get_layers)
664 {
665     dVAR;
666     dXSARGS;
667     if (items < 1 || items % 2 == 0)
668 	croak_xs_usage(cv, "filehandle[,args]");
669 #if defined(USE_PERLIO)
670     {
671 	SV *	sv;
672 	GV *	gv;
673 	IO *	io;
674 	bool	input = TRUE;
675 	bool	details = FALSE;
676 
677 	if (items > 1) {
678 	     SV * const *svp;
679 	     for (svp = MARK + 2; svp <= SP; svp += 2) {
680 		  SV * const * const varp = svp;
681 		  SV * const * const valp = svp + 1;
682 		  STRLEN klen;
683 		  const char * const key = SvPV_const(*varp, klen);
684 
685 		  switch (*key) {
686 		  case 'i':
687 		       if (klen == 5 && memEQ(key, "input", 5)) {
688 			    input = SvTRUE(*valp);
689 			    break;
690 		       }
691 		       goto fail;
692 		  case 'o':
693 		       if (klen == 6 && memEQ(key, "output", 6)) {
694 			    input = !SvTRUE(*valp);
695 			    break;
696 		       }
697 		       goto fail;
698 		  case 'd':
699 		       if (klen == 7 && memEQ(key, "details", 7)) {
700 			    details = SvTRUE(*valp);
701 			    break;
702 		       }
703 		       goto fail;
704 		  default:
705 		  fail:
706 		       Perl_croak(aTHX_
707 				  "get_layers: unknown argument '%s'",
708 				  key);
709 		  }
710 	     }
711 
712 	     SP -= (items - 1);
713 	}
714 
715 	sv = POPs;
716 	gv = MAYBE_DEREF_GV(sv);
717 
718 	if (!gv && !SvROK(sv))
719 	    gv = gv_fetchsv_nomg(sv, 0, SVt_PVIO);
720 
721 	if (gv && (io = GvIO(gv))) {
722 	     AV* const av = PerlIO_get_layers(aTHX_ input ?
723 					IoIFP(io) : IoOFP(io));
724 	     SSize_t i;
725 	     const SSize_t last = av_tindex(av);
726 	     SSize_t nitem = 0;
727 
728 	     for (i = last; i >= 0; i -= 3) {
729 		  SV * const * const namsvp = av_fetch(av, i - 2, FALSE);
730 		  SV * const * const argsvp = av_fetch(av, i - 1, FALSE);
731 		  SV * const * const flgsvp = av_fetch(av, i,     FALSE);
732 
733 		  const bool namok = namsvp && *namsvp && SvPOK(*namsvp);
734 		  const bool argok = argsvp && *argsvp && SvPOK(*argsvp);
735 		  const bool flgok = flgsvp && *flgsvp && SvIOK(*flgsvp);
736 
737 		  EXTEND(SP, 3); /* Three is the max in all branches: better check just once */
738 		  if (details) {
739 		      /* Indents of 5? Yuck.  */
740 		      /* We know that PerlIO_get_layers creates a new SV for
741 			 the name and flags, so we can just take a reference
742 			 and "steal" it when we free the AV below.  */
743 		       PUSHs(namok
744 			      ? sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp))
745 			      : &PL_sv_undef);
746 		       PUSHs(argok
747 			      ? newSVpvn_flags(SvPVX_const(*argsvp),
748 					       SvCUR(*argsvp),
749 					       (SvUTF8(*argsvp) ? SVf_UTF8 : 0)
750 					       | SVs_TEMP)
751 			      : &PL_sv_undef);
752 		       PUSHs(flgok
753 			      ? sv_2mortal(SvREFCNT_inc_simple_NN(*flgsvp))
754 			      : &PL_sv_undef);
755 		       nitem += 3;
756 		  }
757 		  else {
758 		       if (namok && argok)
759 			    PUSHs(sv_2mortal(Perl_newSVpvf(aTHX_ "%"SVf"(%"SVf")",
760 						 SVfARG(*namsvp),
761 						 SVfARG(*argsvp))));
762 		       else if (namok)
763 			    PUSHs(sv_2mortal(SvREFCNT_inc_simple_NN(*namsvp)));
764 		       else
765 			    PUSHs(&PL_sv_undef);
766 		       nitem++;
767 		       if (flgok) {
768 			    const IV flags = SvIVX(*flgsvp);
769 
770 			    if (flags & PERLIO_F_UTF8) {
771 				 PUSHs(newSVpvs_flags("utf8", SVs_TEMP));
772 				 nitem++;
773 			    }
774 		       }
775 		  }
776 	     }
777 
778 	     SvREFCNT_dec(av);
779 
780 	     XSRETURN(nitem);
781 	}
782     }
783 #endif
784 
785     XSRETURN(0);
786 }
787 
788 
789 XS(XS_re_is_regexp); /* prototype to pass -Wmissing-prototypes */
790 XS(XS_re_is_regexp)
791 {
792     dVAR;
793     dXSARGS;
794     PERL_UNUSED_VAR(cv);
795 
796     if (items != 1)
797 	croak_xs_usage(cv, "sv");
798 
799     if (SvRXOK(ST(0))) {
800         XSRETURN_YES;
801     } else {
802         XSRETURN_NO;
803     }
804 }
805 
806 XS(XS_re_regnames_count); /* prototype to pass -Wmissing-prototypes */
807 XS(XS_re_regnames_count)
808 {
809     REGEXP *rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
810     SV * ret;
811     dVAR;
812     dXSARGS;
813 
814     if (items != 0)
815 	croak_xs_usage(cv, "");
816 
817     SP -= items;
818     PUTBACK;
819 
820     if (!rx)
821         XSRETURN_UNDEF;
822 
823     ret = CALLREG_NAMED_BUFF_COUNT(rx);
824 
825     SPAGAIN;
826     PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
827     XSRETURN(1);
828 }
829 
830 XS(XS_re_regname); /* prototype to pass -Wmissing-prototypes */
831 XS(XS_re_regname)
832 {
833     dVAR;
834     dXSARGS;
835     REGEXP * rx;
836     U32 flags;
837     SV * ret;
838 
839     if (items < 1 || items > 2)
840 	croak_xs_usage(cv, "name[, all ]");
841 
842     SP -= items;
843     PUTBACK;
844 
845     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
846 
847     if (!rx)
848         XSRETURN_UNDEF;
849 
850     if (items == 2 && SvTRUE(ST(1))) {
851         flags = RXapif_ALL;
852     } else {
853         flags = RXapif_ONE;
854     }
855     ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(0), (flags | RXapif_REGNAME));
856 
857     SPAGAIN;
858     PUSHs(ret ? sv_2mortal(ret) : &PL_sv_undef);
859     XSRETURN(1);
860 }
861 
862 
863 XS(XS_re_regnames); /* prototype to pass -Wmissing-prototypes */
864 XS(XS_re_regnames)
865 {
866     dVAR;
867     dXSARGS;
868     REGEXP * rx;
869     U32 flags;
870     SV *ret;
871     AV *av;
872     SSize_t length;
873     SSize_t i;
874     SV **entry;
875 
876     if (items > 1)
877 	croak_xs_usage(cv, "[all]");
878 
879     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
880 
881     if (!rx)
882         XSRETURN_UNDEF;
883 
884     if (items == 1 && SvTRUE(ST(0))) {
885         flags = RXapif_ALL;
886     } else {
887         flags = RXapif_ONE;
888     }
889 
890     SP -= items;
891     PUTBACK;
892 
893     ret = CALLREG_NAMED_BUFF_ALL(rx, (flags | RXapif_REGNAMES));
894 
895     SPAGAIN;
896 
897     if (!ret)
898         XSRETURN_UNDEF;
899 
900     av = MUTABLE_AV(SvRV(ret));
901     length = av_tindex(av);
902 
903     EXTEND(SP, length+1); /* better extend stack just once */
904     for (i = 0; i <= length; i++) {
905         entry = av_fetch(av, i, FALSE);
906 
907         if (!entry)
908             Perl_croak(aTHX_ "NULL array element in re::regnames()");
909 
910         mPUSHs(SvREFCNT_inc_simple_NN(*entry));
911     }
912 
913     SvREFCNT_dec(ret);
914 
915     PUTBACK;
916     return;
917 }
918 
919 XS(XS_re_regexp_pattern); /* prototype to pass -Wmissing-prototypes */
920 XS(XS_re_regexp_pattern)
921 {
922     dVAR;
923     dXSARGS;
924     REGEXP *re;
925 
926     EXTEND(SP, 2);
927     SP -= items;
928     if (items != 1)
929 	croak_xs_usage(cv, "sv");
930 
931     /*
932        Checks if a reference is a regex or not. If the parameter is
933        not a ref, or is not the result of a qr// then returns false
934        in scalar context and an empty list in list context.
935        Otherwise in list context it returns the pattern and the
936        modifiers, in scalar context it returns the pattern just as it
937        would if the qr// was stringified normally, regardless as
938        to the class of the variable and any stringification overloads
939        on the object.
940     */
941 
942     if ((re = SvRX(ST(0)))) /* assign deliberate */
943     {
944         /* Houston, we have a regex! */
945         SV *pattern;
946 
947         if ( GIMME_V == G_ARRAY ) {
948 	    STRLEN left = 0;
949 	    char reflags[sizeof(INT_PAT_MODS) + MAX_CHARSET_NAME_LENGTH];
950             const char *fptr;
951             char ch;
952             U16 match_flags;
953 
954             /*
955                we are in list context so stringify
956                the modifiers that apply. We ignore "negative
957                modifiers" in this scenario, and the default character set
958             */
959 
960 	    if (get_regex_charset(RX_EXTFLAGS(re)) != REGEX_DEPENDS_CHARSET) {
961 		STRLEN len;
962 		const char* const name = get_regex_charset_name(RX_EXTFLAGS(re),
963 								&len);
964 		Copy(name, reflags + left, len, char);
965 		left += len;
966 	    }
967             fptr = INT_PAT_MODS;
968             match_flags = (U16)((RX_EXTFLAGS(re) & RXf_PMf_COMPILETIME)
969                                     >> RXf_PMf_STD_PMMOD_SHIFT);
970 
971             while((ch = *fptr++)) {
972                 if(match_flags & 1) {
973                     reflags[left++] = ch;
974                 }
975                 match_flags >>= 1;
976             }
977 
978             pattern = newSVpvn_flags(RX_PRECOMP(re),RX_PRELEN(re),
979 				     (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
980 
981             /* return the pattern and the modifiers */
982             PUSHs(pattern);
983             PUSHs(newSVpvn_flags(reflags, left, SVs_TEMP));
984             XSRETURN(2);
985         } else {
986             /* Scalar, so use the string that Perl would return */
987             /* return the pattern in (?msix:..) format */
988 #if PERL_VERSION >= 11
989             pattern = sv_2mortal(newSVsv(MUTABLE_SV(re)));
990 #else
991             pattern = newSVpvn_flags(RX_WRAPPED(re), RX_WRAPLEN(re),
992 				     (RX_UTF8(re) ? SVf_UTF8 : 0) | SVs_TEMP);
993 #endif
994             PUSHs(pattern);
995             XSRETURN(1);
996         }
997     } else {
998         /* It ain't a regexp folks */
999         if ( GIMME_V == G_ARRAY ) {
1000             /* return the empty list */
1001             XSRETURN_UNDEF;
1002         } else {
1003             /* Because of the (?:..) wrapping involved in a
1004                stringified pattern it is impossible to get a
1005                result for a real regexp that would evaluate to
1006                false. Therefore we can return PL_sv_no to signify
1007                that the object is not a regex, this means that one
1008                can say
1009 
1010                  if (regex($might_be_a_regex) eq '(?:foo)') { }
1011 
1012                and not worry about undefined values.
1013             */
1014             XSRETURN_NO;
1015         }
1016     }
1017     /* NOT-REACHED */
1018 }
1019 
1020 #include "vutil.h"
1021 #include "vxs.inc"
1022 
1023 struct xsub_details {
1024     const char *name;
1025     XSUBADDR_t xsub;
1026     const char *proto;
1027 };
1028 
1029 static const struct xsub_details details[] = {
1030     {"UNIVERSAL::isa", XS_UNIVERSAL_isa, NULL},
1031     {"UNIVERSAL::can", XS_UNIVERSAL_can, NULL},
1032     {"UNIVERSAL::DOES", XS_UNIVERSAL_DOES, NULL},
1033 #define VXS_XSUB_DETAILS
1034 #include "vxs.inc"
1035 #undef VXS_XSUB_DETAILS
1036     {"utf8::is_utf8", XS_utf8_is_utf8, NULL},
1037     {"utf8::valid", XS_utf8_valid, NULL},
1038     {"utf8::encode", XS_utf8_encode, NULL},
1039     {"utf8::decode", XS_utf8_decode, NULL},
1040     {"utf8::upgrade", XS_utf8_upgrade, NULL},
1041     {"utf8::downgrade", XS_utf8_downgrade, NULL},
1042     {"utf8::native_to_unicode", XS_utf8_native_to_unicode, NULL},
1043     {"utf8::unicode_to_native", XS_utf8_unicode_to_native, NULL},
1044     {"Internals::SvREADONLY", XS_Internals_SvREADONLY, "\\[$%@];$"},
1045     {"constant::_make_const", XS_constant__make_const, "\\[$@]"},
1046     {"Internals::SvREFCNT", XS_Internals_SvREFCNT, "\\[$%@];$"},
1047     {"Internals::hv_clear_placeholders", XS_Internals_hv_clear_placehold, "\\%"},
1048     {"PerlIO::get_layers", XS_PerlIO_get_layers, "*;@"},
1049     {"re::is_regexp", XS_re_is_regexp, "$"},
1050     {"re::regname", XS_re_regname, ";$$"},
1051     {"re::regnames", XS_re_regnames, ";$"},
1052     {"re::regnames_count", XS_re_regnames_count, ""},
1053     {"re::regexp_pattern", XS_re_regexp_pattern, "$"},
1054 };
1055 
1056 void
1057 Perl_boot_core_UNIVERSAL(pTHX)
1058 {
1059     dVAR;
1060     static const char file[] = __FILE__;
1061     const struct xsub_details *xsub = details;
1062     const struct xsub_details *end = C_ARRAY_END(details);
1063 
1064     do {
1065 	newXS_flags(xsub->name, xsub->xsub, file, xsub->proto, 0);
1066     } while (++xsub < end);
1067 
1068     /* Providing a Regexp::DESTROY fixes #21347. See test in t/op/ref.t  */
1069     {
1070 	CV * const cv =
1071 	    newCONSTSUB(get_hv("Regexp::", GV_ADD), "DESTROY", NULL);
1072 	Safefree(CvFILE(cv));
1073 	CvFILE(cv) = (char *)file;
1074 	CvDYNFILE_off(cv);
1075     }
1076 }
1077 
1078 /*
1079  * Local variables:
1080  * c-indentation-style: bsd
1081  * c-basic-offset: 4
1082  * indent-tabs-mode: nil
1083  * End:
1084  *
1085  * ex: set ts=8 sts=4 sw=4 et:
1086  */
1087