This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: [PATCH] Callbacks for named captures (%+ and %-)
[perl5.git] / universal.c
1 /*    universal.c
2  *
3  *    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4  *    2005, 2006, 2007 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 story
15  */
16
17 /* This file contains the code that implements the functions in Perl's
18  * UNIVERSAL package, such as UNIVERSAL->can().
19  *
20  * It is also used to store XS functions that need to be present in
21  * miniperl for a lack of a better place to put them. It might be
22  * clever to move them to seperate XS files which would then be pulled
23  * in by some to-be-written build process.
24  */
25
26 #include "EXTERN.h"
27 #define PERL_IN_UNIVERSAL_C
28 #include "perl.h"
29
30 #ifdef USE_PERLIO
31 #include "perliol.h" /* For the PERLIO_F_XXX */
32 #endif
33
34 /*
35  * Contributed by Graham Barr  <Graham.Barr@tiuk.ti.com>
36  * The main guts of traverse_isa was actually copied from gv_fetchmeth
37  */
38
39 STATIC bool
40 S_isa_lookup(pTHX_ HV *stash, const char * const name, const HV* const name_stash)
41 {
42     dVAR;
43     AV* stash_linear_isa;
44     SV** svp;
45     const char *hvname;
46     I32 items;
47
48     /* A stash/class can go by many names (ie. User == main::User), so 
49        we compare the stash itself just in case */
50     if (name_stash && ((const HV *)stash == name_stash))
51         return TRUE;
52
53     hvname = HvNAME_get(stash);
54
55     if (strEQ(hvname, name))
56         return TRUE;
57
58     if (strEQ(name, "UNIVERSAL"))
59         return TRUE;
60
61     stash_linear_isa = mro_get_linear_isa(stash);
62     svp = AvARRAY(stash_linear_isa) + 1;
63     items = AvFILLp(stash_linear_isa);
64     while (items--) {
65         SV* const basename_sv = *svp++;
66         HV* const basestash = gv_stashsv(basename_sv, 0);
67         if (!basestash) {
68             if (ckWARN(WARN_SYNTAX))
69                 Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
70                             "Can't locate package %"SVf" for the parents of %s",
71                             SVfARG(basename_sv), hvname);
72             continue;
73         }
74         if(name_stash == basestash || strEQ(name, SvPVX(basename_sv)))
75             return TRUE;
76     }
77
78     return FALSE;
79 }
80
81 /*
82 =head1 SV Manipulation Functions
83
84 =for apidoc sv_derived_from
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 =cut
91 */
92
93 bool
94 Perl_sv_derived_from(pTHX_ SV *sv, const char *name)
95 {
96     dVAR;
97     HV *stash;
98
99     SvGETMAGIC(sv);
100
101     if (SvROK(sv)) {
102         const char *type;
103         sv = SvRV(sv);
104         type = sv_reftype(sv,0);
105         if (type && strEQ(type,name))
106             return TRUE;
107         stash = SvOBJECT(sv) ? SvSTASH(sv) : NULL;
108     }
109     else {
110         stash = gv_stashsv(sv, 0);
111     }
112
113     if (stash) {
114         HV * const name_stash = gv_stashpv(name, 0);
115         return isa_lookup(stash, name, name_stash);
116     }
117     else
118         return FALSE;
119
120 }
121
122 /*
123 =for apidoc sv_does
124
125 Returns a boolean indicating whether the SV performs a specific, named role.
126 The SV can be a Perl object or the name of a Perl class.
127
128 =cut
129 */
130
131 #include "XSUB.h"
132
133 bool
134 Perl_sv_does(pTHX_ SV *sv, const char *name)
135 {
136     const char *classname;
137     bool does_it;
138     SV *methodname;
139
140     dSP;
141     ENTER;
142     SAVETMPS;
143
144     SvGETMAGIC(sv);
145
146     if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
147                 || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
148         return FALSE;
149
150     if (sv_isobject(sv)) {
151         classname = sv_reftype(SvRV(sv),TRUE);
152     } else {
153         classname = SvPV_nolen(sv);
154     }
155
156     if (strEQ(name,classname))
157         return TRUE;
158
159     PUSHMARK(SP);
160     XPUSHs(sv);
161     XPUSHs(sv_2mortal(newSVpv(name, 0)));
162     PUTBACK;
163
164     methodname = sv_2mortal(newSVpv("isa", 0));
165     /* ugly hack: use the SvSCREAM flag so S_method_common
166      * can figure out we're calling DOES() and not isa(),
167      * and report eventual errors correctly. --rgs */
168     SvSCREAM_on(methodname);
169     call_sv(methodname, G_SCALAR | G_METHOD);
170     SPAGAIN;
171
172     does_it = SvTRUE( TOPs );
173     FREETMPS;
174     LEAVE;
175
176     return does_it;
177 }
178
179 regexp *
180 Perl_get_re_arg( pTHX_ SV *sv, U32 flags, MAGIC **mgp) {
181     MAGIC *mg;
182     if (sv) {
183         if (SvMAGICAL(sv))
184             mg_get(sv);
185         if (SvROK(sv) &&
186             (sv = (SV*)SvRV(sv)) &&     /* assign deliberate */
187             SvTYPE(sv) == SVt_PVMG &&
188             (mg = mg_find(sv, PERL_MAGIC_qr))) /* assign deliberate */
189         {        
190             if (mgp) *mgp = mg;
191             return (regexp *)mg->mg_obj;       
192         }
193     }    
194     if (mgp) *mgp = NULL;
195     return ((flags && PL_curpm) ? PM_GETRE(PL_curpm) : NULL);
196 }
197
198
199 PERL_XS_EXPORT_C void XS_UNIVERSAL_isa(pTHX_ CV *cv);
200 PERL_XS_EXPORT_C void XS_UNIVERSAL_can(pTHX_ CV *cv);
201 PERL_XS_EXPORT_C void XS_UNIVERSAL_DOES(pTHX_ CV *cv);
202 PERL_XS_EXPORT_C void XS_UNIVERSAL_VERSION(pTHX_ CV *cv);
203 XS(XS_version_new);
204 XS(XS_version_stringify);
205 XS(XS_version_numify);
206 XS(XS_version_normal);
207 XS(XS_version_vcmp);
208 XS(XS_version_boolean);
209 #ifdef HASATTRIBUTE_NORETURN
210 XS(XS_version_noop) __attribute__noreturn__;
211 #else
212 XS(XS_version_noop);
213 #endif
214 XS(XS_version_is_alpha);
215 XS(XS_version_qv);
216 XS(XS_utf8_is_utf8);
217 XS(XS_utf8_valid);
218 XS(XS_utf8_encode);
219 XS(XS_utf8_decode);
220 XS(XS_utf8_upgrade);
221 XS(XS_utf8_downgrade);
222 XS(XS_utf8_unicode_to_native);
223 XS(XS_utf8_native_to_unicode);
224 XS(XS_Internals_SvREADONLY);
225 XS(XS_Internals_SvREFCNT);
226 XS(XS_Internals_hv_clear_placehold);
227 XS(XS_PerlIO_get_layers);
228 XS(XS_Regexp_DESTROY);
229 XS(XS_Internals_hash_seed);
230 XS(XS_Internals_rehash_seed);
231 XS(XS_Internals_HvREHASH);
232 XS(XS_Internals_inc_sub_generation);
233 XS(XS_re_is_regexp); 
234 XS(XS_re_regname);
235 XS(XS_re_regnames);
236 XS(XS_re_regnames_count);
237 XS(XS_Tie_Hash_NamedCapture_FETCH);
238 XS(XS_Tie_Hash_NamedCapture_STORE);
239 XS(XS_Tie_Hash_NamedCapture_DELETE);
240 XS(XS_Tie_Hash_NamedCapture_CLEAR);
241 XS(XS_Tie_Hash_NamedCapture_EXISTS);
242 XS(XS_Tie_Hash_NamedCapture_FIRSTKEY);
243 XS(XS_Tie_Hash_NamedCapture_NEXTKEY);
244 XS(XS_Tie_Hash_NamedCapture_SCALAR);
245 XS(XS_Tie_Hash_NamedCapture_flags);
246
247 void
248 Perl_boot_core_UNIVERSAL(pTHX)
249 {
250     dVAR;
251     static const char file[] = __FILE__;
252
253     newXS("UNIVERSAL::isa",             XS_UNIVERSAL_isa,         file);
254     newXS("UNIVERSAL::can",             XS_UNIVERSAL_can,         file);
255     newXS("UNIVERSAL::DOES",            XS_UNIVERSAL_DOES,        file);
256     newXS("UNIVERSAL::VERSION",         XS_UNIVERSAL_VERSION,     file);
257     {
258         /* register the overloading (type 'A') magic */
259         PL_amagic_generation++;
260         /* Make it findable via fetchmethod */
261         newXS("version::()", XS_version_noop, file);
262         newXS("version::new", XS_version_new, file);
263         newXS("version::(\"\"", XS_version_stringify, file);
264         newXS("version::stringify", XS_version_stringify, file);
265         newXS("version::(0+", XS_version_numify, file);
266         newXS("version::numify", XS_version_numify, file);
267         newXS("version::normal", XS_version_normal, file);
268         newXS("version::(cmp", XS_version_vcmp, file);
269         newXS("version::(<=>", XS_version_vcmp, file);
270         newXS("version::vcmp", XS_version_vcmp, file);
271         newXS("version::(bool", XS_version_boolean, file);
272         newXS("version::boolean", XS_version_boolean, file);
273         newXS("version::(nomethod", XS_version_noop, file);
274         newXS("version::noop", XS_version_noop, file);
275         newXS("version::is_alpha", XS_version_is_alpha, file);
276         newXS("version::qv", XS_version_qv, file);
277     }
278     newXS("utf8::is_utf8", XS_utf8_is_utf8, file);
279     newXS("utf8::valid", XS_utf8_valid, file);
280     newXS("utf8::encode", XS_utf8_encode, file);
281     newXS("utf8::decode", XS_utf8_decode, file);
282     newXS("utf8::upgrade", XS_utf8_upgrade, file);
283     newXS("utf8::downgrade", XS_utf8_downgrade, file);
284     newXS("utf8::native_to_unicode", XS_utf8_native_to_unicode, file);
285     newXS("utf8::unicode_to_native", XS_utf8_unicode_to_native, file);
286     newXSproto("Internals::SvREADONLY",XS_Internals_SvREADONLY, file, "\\[$%@];$");
287     newXSproto("Internals::SvREFCNT",XS_Internals_SvREFCNT, file, "\\[$%@];$");
288     newXSproto("Internals::hv_clear_placeholders",
289                XS_Internals_hv_clear_placehold, file, "\\%");
290     newXSproto("PerlIO::get_layers",
291                XS_PerlIO_get_layers, file, "*;@");
292     newXS("Regexp::DESTROY", XS_Regexp_DESTROY, file);
293     newXSproto("Internals::hash_seed",XS_Internals_hash_seed, file, "");
294     newXSproto("Internals::rehash_seed",XS_Internals_rehash_seed, file, "");
295     newXSproto("Internals::HvREHASH", XS_Internals_HvREHASH, file, "\\%");
296     newXSproto("re::is_regexp", XS_re_is_regexp, file, "$");
297     newXSproto("re::regname", XS_re_regname, file, ";$$");
298     newXSproto("re::regnames", XS_re_regnames, file, ";$");
299     newXSproto("re::regnames_count", XS_re_regnames_count, file, "");
300     newXS("Tie::Hash::NamedCapture::FETCH", XS_Tie_Hash_NamedCapture_FETCH, file);
301     newXS("Tie::Hash::NamedCapture::STORE", XS_Tie_Hash_NamedCapture_STORE, file);
302     newXS("Tie::Hash::NamedCapture::DELETE", XS_Tie_Hash_NamedCapture_DELETE, file);
303     newXS("Tie::Hash::NamedCapture::CLEAR", XS_Tie_Hash_NamedCapture_CLEAR, file);
304     newXS("Tie::Hash::NamedCapture::EXISTS", XS_Tie_Hash_NamedCapture_EXISTS, file);
305     newXS("Tie::Hash::NamedCapture::FIRSTKEY", XS_Tie_Hash_NamedCapture_FIRSTKEY, file);
306     newXS("Tie::Hash::NamedCapture::NEXTKEY", XS_Tie_Hash_NamedCapture_NEXTKEY, file);
307     newXS("Tie::Hash::NamedCapture::SCALAR", XS_Tie_Hash_NamedCapture_SCALAR, file);
308     newXS("Tie::Hash::NamedCapture::flags", XS_Tie_Hash_NamedCapture_flags, file);
309 }
310
311
312 XS(XS_UNIVERSAL_isa)
313 {
314     dVAR;
315     dXSARGS;
316     PERL_UNUSED_ARG(cv);
317
318     if (items != 2)
319         Perl_croak(aTHX_ "Usage: UNIVERSAL::isa(reference, kind)");
320     else {
321         SV * const sv = ST(0);
322         const char *name;
323
324         SvGETMAGIC(sv);
325
326         if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
327                     || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
328             XSRETURN_UNDEF;
329
330         name = SvPV_nolen_const(ST(1));
331
332         ST(0) = boolSV(sv_derived_from(sv, name));
333         XSRETURN(1);
334     }
335 }
336
337 XS(XS_UNIVERSAL_can)
338 {
339     dVAR;
340     dXSARGS;
341     SV   *sv;
342     const char *name;
343     SV   *rv;
344     HV   *pkg = NULL;
345     PERL_UNUSED_ARG(cv);
346
347     if (items != 2)
348         Perl_croak(aTHX_ "Usage: UNIVERSAL::can(object-ref, method)");
349
350     sv = ST(0);
351
352     SvGETMAGIC(sv);
353
354     if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
355                 || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
356         XSRETURN_UNDEF;
357
358     name = SvPV_nolen_const(ST(1));
359     rv = &PL_sv_undef;
360
361     if (SvROK(sv)) {
362         sv = (SV*)SvRV(sv);
363         if (SvOBJECT(sv))
364             pkg = SvSTASH(sv);
365     }
366     else {
367         pkg = gv_stashsv(sv, 0);
368     }
369
370     if (pkg) {
371         GV * const gv = gv_fetchmethod_autoload(pkg, name, FALSE);
372         if (gv && isGV(gv))
373             rv = sv_2mortal(newRV((SV*)GvCV(gv)));
374     }
375
376     ST(0) = rv;
377     XSRETURN(1);
378 }
379
380 XS(XS_UNIVERSAL_DOES)
381 {
382     dVAR;
383     dXSARGS;
384     PERL_UNUSED_ARG(cv);
385
386     if (items != 2)
387         Perl_croak(aTHX_ "Usage: invocant->DOES(kind)");
388     else {
389         SV * const sv = ST(0);
390         const char *name;
391
392         name = SvPV_nolen_const(ST(1));
393         if (sv_does( sv, name ))
394             XSRETURN_YES;
395
396         XSRETURN_NO;
397     }
398 }
399
400 XS(XS_UNIVERSAL_VERSION)
401 {
402     dVAR;
403     dXSARGS;
404     HV *pkg;
405     GV **gvp;
406     GV *gv;
407     SV *sv;
408     const char *undef;
409     PERL_UNUSED_ARG(cv);
410
411     if (SvROK(ST(0))) {
412         sv = (SV*)SvRV(ST(0));
413         if (!SvOBJECT(sv))
414             Perl_croak(aTHX_ "Cannot find version of an unblessed reference");
415         pkg = SvSTASH(sv);
416     }
417     else {
418         pkg = gv_stashsv(ST(0), 0);
419     }
420
421     gvp = pkg ? (GV**)hv_fetchs(pkg, "VERSION", FALSE) : NULL;
422
423     if (gvp && isGV(gv = *gvp) && (sv = GvSV(gv)) && SvOK(sv)) {
424         SV * const nsv = sv_newmortal();
425         sv_setsv(nsv, sv);
426         sv = nsv;
427         if ( !sv_derived_from(sv, "version"))
428             upg_version(sv, FALSE);
429         undef = NULL;
430     }
431     else {
432         sv = (SV*)&PL_sv_undef;
433         undef = "(undef)";
434     }
435
436     if (items > 1) {
437         SV *req = ST(1);
438
439         if (undef) {
440             if (pkg) {
441                 const char * const name = HvNAME_get(pkg);
442                 Perl_croak(aTHX_
443                            "%s does not define $%s::VERSION--version check failed",
444                            name, name);
445             } else {
446                 Perl_croak(aTHX_
447                              "%s defines neither package nor VERSION--version check failed",
448                              SvPVx_nolen_const(ST(0)) );
449              }
450         }
451
452         if ( !sv_derived_from(req, "version")) {
453             /* req may very well be R/O, so create a new object */
454             req = sv_2mortal( new_version(req) );
455         }
456
457         if ( vcmp( req, sv ) > 0 ) {
458             if ( hv_exists((HV*)SvRV(req), "qv", 2 ) ) {
459                 Perl_croak(aTHX_ "%s version %"SVf" required--"
460                        "this is only version %"SVf"", HvNAME_get(pkg),
461                        SVfARG(vnormal(req)),
462                        SVfARG(vnormal(sv)));
463             } else {
464                 Perl_croak(aTHX_ "%s version %"SVf" required--"
465                        "this is only version %"SVf"", HvNAME_get(pkg),
466                        SVfARG(vstringify(req)),
467                        SVfARG(vstringify(sv)));
468             }
469         }
470
471     }
472
473     if ( SvOK(sv) && sv_derived_from(sv, "version") ) {
474         ST(0) = vstringify(sv);
475     } else {
476         ST(0) = sv;
477     }
478
479     XSRETURN(1);
480 }
481
482 XS(XS_version_new)
483 {
484     dVAR;
485     dXSARGS;
486     PERL_UNUSED_ARG(cv);
487     if (items > 3)
488         Perl_croak(aTHX_ "Usage: version::new(class, version)");
489     SP -= items;
490     {
491         SV *vs = ST(1);
492         SV *rv;
493         const char * const classname =
494             sv_isobject(ST(0)) /* get the class if called as an object method */
495                 ? HvNAME(SvSTASH(SvRV(ST(0))))
496                 : (char *)SvPV_nolen(ST(0));
497
498         if ( items == 1 || vs == &PL_sv_undef ) { /* no param or explicit undef */
499             /* create empty object */
500             vs = sv_newmortal();
501             sv_setpvn(vs,"",0);
502         }
503         else if ( items == 3 ) {
504             vs = sv_newmortal();
505             Perl_sv_setpvf(aTHX_ vs,"v%s",SvPV_nolen_const(ST(2)));
506         }
507
508         rv = new_version(vs);
509         if ( strcmp(classname,"version") != 0 ) /* inherited new() */
510             sv_bless(rv, gv_stashpv(classname, GV_ADD));
511
512         PUSHs(sv_2mortal(rv));
513         PUTBACK;
514         return;
515     }
516 }
517
518 XS(XS_version_stringify)
519 {
520      dVAR;
521      dXSARGS;
522      PERL_UNUSED_ARG(cv);
523      if (items < 1)
524           Perl_croak(aTHX_ "Usage: version::stringify(lobj, ...)");
525      SP -= items;
526      {
527           SV *  lobj;
528
529           if (sv_derived_from(ST(0), "version")) {
530                lobj = SvRV(ST(0));
531           }
532           else
533                Perl_croak(aTHX_ "lobj is not of type version");
534
535           PUSHs(sv_2mortal(vstringify(lobj)));
536
537           PUTBACK;
538           return;
539      }
540 }
541
542 XS(XS_version_numify)
543 {
544      dVAR;
545      dXSARGS;
546      PERL_UNUSED_ARG(cv);
547      if (items < 1)
548           Perl_croak(aTHX_ "Usage: version::numify(lobj, ...)");
549      SP -= items;
550      {
551           SV *  lobj;
552
553           if (sv_derived_from(ST(0), "version")) {
554                lobj = SvRV(ST(0));
555           }
556           else
557                Perl_croak(aTHX_ "lobj is not of type version");
558
559           PUSHs(sv_2mortal(vnumify(lobj)));
560
561           PUTBACK;
562           return;
563      }
564 }
565
566 XS(XS_version_normal)
567 {
568      dVAR;
569      dXSARGS;
570      PERL_UNUSED_ARG(cv);
571      if (items < 1)
572           Perl_croak(aTHX_ "Usage: version::normal(lobj, ...)");
573      SP -= items;
574      {
575           SV *  lobj;
576
577           if (sv_derived_from(ST(0), "version")) {
578                lobj = SvRV(ST(0));
579           }
580           else
581                Perl_croak(aTHX_ "lobj is not of type version");
582
583           PUSHs(sv_2mortal(vnormal(lobj)));
584
585           PUTBACK;
586           return;
587      }
588 }
589
590 XS(XS_version_vcmp)
591 {
592      dVAR;
593      dXSARGS;
594      PERL_UNUSED_ARG(cv);
595      if (items < 1)
596           Perl_croak(aTHX_ "Usage: version::vcmp(lobj, ...)");
597      SP -= items;
598      {
599           SV *  lobj;
600
601           if (sv_derived_from(ST(0), "version")) {
602                lobj = SvRV(ST(0));
603           }
604           else
605                Perl_croak(aTHX_ "lobj is not of type version");
606
607           {
608                SV       *rs;
609                SV       *rvs;
610                SV * robj = ST(1);
611                const IV  swap = (IV)SvIV(ST(2));
612
613                if ( ! sv_derived_from(robj, "version") )
614                {
615                     robj = new_version(robj);
616                }
617                rvs = SvRV(robj);
618
619                if ( swap )
620                {
621                     rs = newSViv(vcmp(rvs,lobj));
622                }
623                else
624                {
625                     rs = newSViv(vcmp(lobj,rvs));
626                }
627
628                PUSHs(sv_2mortal(rs));
629           }
630
631           PUTBACK;
632           return;
633      }
634 }
635
636 XS(XS_version_boolean)
637 {
638     dVAR;
639     dXSARGS;
640     PERL_UNUSED_ARG(cv);
641     if (items < 1)
642         Perl_croak(aTHX_ "Usage: version::boolean(lobj, ...)");
643     SP -= items;
644     if (sv_derived_from(ST(0), "version")) {
645         SV * const lobj = SvRV(ST(0));
646         SV * const rs = newSViv( vcmp(lobj,new_version(newSVpvs("0"))) );
647         PUSHs(sv_2mortal(rs));
648         PUTBACK;
649         return;
650     }
651     else
652         Perl_croak(aTHX_ "lobj is not of type version");
653 }
654
655 XS(XS_version_noop)
656 {
657     dVAR;
658     dXSARGS;
659     PERL_UNUSED_ARG(cv);
660     if (items < 1)
661         Perl_croak(aTHX_ "Usage: version::noop(lobj, ...)");
662     if (sv_derived_from(ST(0), "version"))
663         Perl_croak(aTHX_ "operation not supported with version object");
664     else
665         Perl_croak(aTHX_ "lobj is not of type version");
666 #ifndef HASATTRIBUTE_NORETURN
667     XSRETURN_EMPTY;
668 #endif
669 }
670
671 XS(XS_version_is_alpha)
672 {
673     dVAR;
674     dXSARGS;
675     PERL_UNUSED_ARG(cv);
676     if (items != 1)
677         Perl_croak(aTHX_ "Usage: version::is_alpha(lobj)");
678     SP -= items;
679     if (sv_derived_from(ST(0), "version")) {
680         SV * const lobj = ST(0);
681         if ( hv_exists((HV*)SvRV(lobj), "alpha", 5 ) )
682             XSRETURN_YES;
683         else
684             XSRETURN_NO;
685         PUTBACK;
686         return;
687     }
688     else
689         Perl_croak(aTHX_ "lobj is not of type version");
690 }
691
692 XS(XS_version_qv)
693 {
694     dVAR;
695     dXSARGS;
696     PERL_UNUSED_ARG(cv);
697     if (items != 1)
698         Perl_croak(aTHX_ "Usage: version::qv(ver)");
699     SP -= items;
700     {
701         SV *    ver = ST(0);
702         if ( !SvVOK(ver) ) { /* only need to do with if not already v-string */
703             SV * const rv = sv_newmortal();
704             sv_setsv(rv,ver); /* make a duplicate */
705             upg_version(rv, TRUE);
706             PUSHs(rv);
707         }
708         else
709         {
710             PUSHs(sv_2mortal(new_version(ver)));
711         }
712
713         PUTBACK;
714         return;
715     }
716 }
717
718 XS(XS_utf8_is_utf8)
719 {
720      dVAR;
721      dXSARGS;
722      PERL_UNUSED_ARG(cv);
723      if (items != 1)
724           Perl_croak(aTHX_ "Usage: utf8::is_utf8(sv)");
725      else {
726         const SV * const sv = ST(0);
727             if (SvUTF8(sv))
728                 XSRETURN_YES;
729             else
730                 XSRETURN_NO;
731      }
732      XSRETURN_EMPTY;
733 }
734
735 XS(XS_utf8_valid)
736 {
737      dVAR;
738      dXSARGS;
739      PERL_UNUSED_ARG(cv);
740      if (items != 1)
741           Perl_croak(aTHX_ "Usage: utf8::valid(sv)");
742     else {
743         SV * const sv = ST(0);
744         STRLEN len;
745         const char * const s = SvPV_const(sv,len);
746         if (!SvUTF8(sv) || is_utf8_string((const U8*)s,len))
747             XSRETURN_YES;
748         else
749             XSRETURN_NO;
750     }
751      XSRETURN_EMPTY;
752 }
753
754 XS(XS_utf8_encode)
755 {
756     dVAR;
757     dXSARGS;
758     PERL_UNUSED_ARG(cv);
759     if (items != 1)
760         Perl_croak(aTHX_ "Usage: utf8::encode(sv)");
761     sv_utf8_encode(ST(0));
762     XSRETURN_EMPTY;
763 }
764
765 XS(XS_utf8_decode)
766 {
767     dVAR;
768     dXSARGS;
769     PERL_UNUSED_ARG(cv);
770     if (items != 1)
771         Perl_croak(aTHX_ "Usage: utf8::decode(sv)");
772     else {
773         SV * const sv = ST(0);
774         const bool RETVAL = sv_utf8_decode(sv);
775         ST(0) = boolSV(RETVAL);
776         sv_2mortal(ST(0));
777     }
778     XSRETURN(1);
779 }
780
781 XS(XS_utf8_upgrade)
782 {
783     dVAR;
784     dXSARGS;
785     PERL_UNUSED_ARG(cv);
786     if (items != 1)
787         Perl_croak(aTHX_ "Usage: utf8::upgrade(sv)");
788     else {
789         SV * const sv = ST(0);
790         STRLEN  RETVAL;
791         dXSTARG;
792
793         RETVAL = sv_utf8_upgrade(sv);
794         XSprePUSH; PUSHi((IV)RETVAL);
795     }
796     XSRETURN(1);
797 }
798
799 XS(XS_utf8_downgrade)
800 {
801     dVAR;
802     dXSARGS;
803     PERL_UNUSED_ARG(cv);
804     if (items < 1 || items > 2)
805         Perl_croak(aTHX_ "Usage: utf8::downgrade(sv, failok=0)");
806     else {
807         SV * const sv = ST(0);
808         const bool failok = (items < 2) ? 0 : (int)SvIV(ST(1));
809         const bool RETVAL = sv_utf8_downgrade(sv, failok);
810
811         ST(0) = boolSV(RETVAL);
812         sv_2mortal(ST(0));
813     }
814     XSRETURN(1);
815 }
816
817 XS(XS_utf8_native_to_unicode)
818 {
819  dVAR;
820  dXSARGS;
821  const UV uv = SvUV(ST(0));
822  PERL_UNUSED_ARG(cv);
823
824  if (items > 1)
825      Perl_croak(aTHX_ "Usage: utf8::native_to_unicode(sv)");
826
827  ST(0) = sv_2mortal(newSViv(NATIVE_TO_UNI(uv)));
828  XSRETURN(1);
829 }
830
831 XS(XS_utf8_unicode_to_native)
832 {
833  dVAR;
834  dXSARGS;
835  const UV uv = SvUV(ST(0));
836  PERL_UNUSED_ARG(cv);
837
838  if (items > 1)
839      Perl_croak(aTHX_ "Usage: utf8::unicode_to_native(sv)");
840
841  ST(0) = sv_2mortal(newSViv(UNI_TO_NATIVE(uv)));
842  XSRETURN(1);
843 }
844
845 XS(XS_Internals_SvREADONLY)     /* This is dangerous stuff. */
846 {
847     dVAR;
848     dXSARGS;
849     SV * const sv = SvRV(ST(0));
850     PERL_UNUSED_ARG(cv);
851
852     if (items == 1) {
853          if (SvREADONLY(sv))
854              XSRETURN_YES;
855          else
856              XSRETURN_NO;
857     }
858     else if (items == 2) {
859         if (SvTRUE(ST(1))) {
860             SvREADONLY_on(sv);
861             XSRETURN_YES;
862         }
863         else {
864             /* I hope you really know what you are doing. */
865             SvREADONLY_off(sv);
866             XSRETURN_NO;
867         }
868     }
869     XSRETURN_UNDEF; /* Can't happen. */
870 }
871
872 XS(XS_Internals_SvREFCNT)       /* This is dangerous stuff. */
873 {
874     dVAR;
875     dXSARGS;
876     SV * const sv = SvRV(ST(0));
877     PERL_UNUSED_ARG(cv);
878
879     if (items == 1)
880          XSRETURN_IV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */
881     else if (items == 2) {
882          /* I hope you really know what you are doing. */
883          SvREFCNT(sv) = SvIV(ST(1));
884          XSRETURN_IV(SvREFCNT(sv));
885     }
886     XSRETURN_UNDEF; /* Can't happen. */
887 }
888
889 XS(XS_Internals_hv_clear_placehold)
890 {
891     dVAR;
892     dXSARGS;
893     PERL_UNUSED_ARG(cv);
894
895     if (items != 1)
896         Perl_croak(aTHX_ "Usage: UNIVERSAL::hv_clear_placeholders(hv)");
897     else {
898         HV * const hv = (HV *) SvRV(ST(0));
899         hv_clear_placeholders(hv);
900         XSRETURN(0);
901     }
902 }
903
904 XS(XS_Regexp_DESTROY)
905 {
906     PERL_UNUSED_CONTEXT;
907     PERL_UNUSED_ARG(cv);
908 }
909
910 XS(XS_PerlIO_get_layers)
911 {
912     dVAR;
913     dXSARGS;
914     PERL_UNUSED_ARG(cv);
915     if (items < 1 || items % 2 == 0)
916         Perl_croak(aTHX_ "Usage: PerlIO_get_layers(filehandle[,args])");
917 #ifdef USE_PERLIO
918     {
919         SV *    sv;
920         GV *    gv;
921         IO *    io;
922         bool    input = TRUE;
923         bool    details = FALSE;
924
925         if (items > 1) {
926              SV * const *svp;
927              for (svp = MARK + 2; svp <= SP; svp += 2) {
928                   SV * const * const varp = svp;
929                   SV * const * const valp = svp + 1;
930                   STRLEN klen;
931                   const char * const key = SvPV_const(*varp, klen);
932
933                   switch (*key) {
934                   case 'i':
935                        if (klen == 5 && memEQ(key, "input", 5)) {
936                             input = SvTRUE(*valp);
937                             break;
938                        }
939                        goto fail;
940                   case 'o': 
941                        if (klen == 6 && memEQ(key, "output", 6)) {
942                             input = !SvTRUE(*valp);
943                             break;
944                        }
945                        goto fail;
946                   case 'd':
947                        if (klen == 7 && memEQ(key, "details", 7)) {
948                             details = SvTRUE(*valp);
949                             break;
950                        }
951                        goto fail;
952                   default:
953                   fail:
954                        Perl_croak(aTHX_
955                                   "get_layers: unknown argument '%s'",
956                                   key);
957                   }
958              }
959
960              SP -= (items - 1);
961         }
962
963         sv = POPs;
964         gv = (GV*)sv;
965
966         if (!isGV(sv)) {
967              if (SvROK(sv) && isGV(SvRV(sv)))
968                   gv = (GV*)SvRV(sv);
969              else if (SvPOKp(sv))
970                   gv = gv_fetchsv(sv, 0, SVt_PVIO);
971         }
972
973         if (gv && (io = GvIO(gv))) {
974              dTARGET;
975              AV* const av = PerlIO_get_layers(aTHX_ input ?
976                                         IoIFP(io) : IoOFP(io));
977              I32 i;
978              const I32 last = av_len(av);
979              I32 nitem = 0;
980              
981              for (i = last; i >= 0; i -= 3) {
982                   SV * const * const namsvp = av_fetch(av, i - 2, FALSE);
983                   SV * const * const argsvp = av_fetch(av, i - 1, FALSE);
984                   SV * const * const flgsvp = av_fetch(av, i,     FALSE);
985
986                   const bool namok = namsvp && *namsvp && SvPOK(*namsvp);
987                   const bool argok = argsvp && *argsvp && SvPOK(*argsvp);
988                   const bool flgok = flgsvp && *flgsvp && SvIOK(*flgsvp);
989
990                   if (details) {
991                        XPUSHs(namok
992                               ? newSVpvn(SvPVX_const(*namsvp), SvCUR(*namsvp))
993                               : &PL_sv_undef);
994                        XPUSHs(argok
995                               ? newSVpvn(SvPVX_const(*argsvp), SvCUR(*argsvp))
996                               : &PL_sv_undef);
997                        if (flgok)
998                             XPUSHi(SvIVX(*flgsvp));
999                        else
1000                             XPUSHs(&PL_sv_undef);
1001                        nitem += 3;
1002                   }
1003                   else {
1004                        if (namok && argok)
1005                             XPUSHs(Perl_newSVpvf(aTHX_ "%"SVf"(%"SVf")",
1006                                                  SVfARG(*namsvp),
1007                                                  SVfARG(*argsvp)));
1008                        else if (namok)
1009                             XPUSHs(Perl_newSVpvf(aTHX_ "%"SVf,
1010                                                  SVfARG(*namsvp)));
1011                        else
1012                             XPUSHs(&PL_sv_undef);
1013                        nitem++;
1014                        if (flgok) {
1015                             const IV flags = SvIVX(*flgsvp);
1016
1017                             if (flags & PERLIO_F_UTF8) {
1018                                  XPUSHs(newSVpvs("utf8"));
1019                                  nitem++;
1020                             }
1021                        }
1022                   }
1023              }
1024
1025              SvREFCNT_dec(av);
1026
1027              XSRETURN(nitem);
1028         }
1029     }
1030 #endif
1031
1032     XSRETURN(0);
1033 }
1034
1035 XS(XS_Internals_hash_seed)
1036 {
1037     dVAR;
1038     /* Using dXSARGS would also have dITEM and dSP,
1039      * which define 2 unused local variables.  */
1040     dAXMARK;
1041     PERL_UNUSED_ARG(cv);
1042     PERL_UNUSED_VAR(mark);
1043     XSRETURN_UV(PERL_HASH_SEED);
1044 }
1045
1046 XS(XS_Internals_rehash_seed)
1047 {
1048     dVAR;
1049     /* Using dXSARGS would also have dITEM and dSP,
1050      * which define 2 unused local variables.  */
1051     dAXMARK;
1052     PERL_UNUSED_ARG(cv);
1053     PERL_UNUSED_VAR(mark);
1054     XSRETURN_UV(PL_rehash_seed);
1055 }
1056
1057 XS(XS_Internals_HvREHASH)       /* Subject to change  */
1058 {
1059     dVAR;
1060     dXSARGS;
1061     PERL_UNUSED_ARG(cv);
1062     if (SvROK(ST(0))) {
1063         const HV * const hv = (HV *) SvRV(ST(0));
1064         if (items == 1 && SvTYPE(hv) == SVt_PVHV) {
1065             if (HvREHASH(hv))
1066                 XSRETURN_YES;
1067             else
1068                 XSRETURN_NO;
1069         }
1070     }
1071     Perl_croak(aTHX_ "Internals::HvREHASH $hashref");
1072 }
1073
1074 XS(XS_re_is_regexp)
1075 {
1076     dVAR; 
1077     dXSARGS;
1078     if (items != 1)
1079        Perl_croak(aTHX_ "Usage: %s(%s)", "re::is_regexp", "sv");
1080     PERL_UNUSED_VAR(cv); /* -W */
1081     PERL_UNUSED_VAR(ax); /* -Wall */
1082     SP -= items;
1083     {
1084         SV *    sv = ST(0);
1085         if ( Perl_get_re_arg( aTHX_ sv, 0, NULL ) ) 
1086         {
1087             XSRETURN_YES;
1088         } else {
1089             XSRETURN_NO;
1090         }
1091         /* NOTREACHED */        
1092         PUTBACK;
1093         return;
1094     }
1095 }
1096
1097 XS(XS_re_regnames_count)
1098 {
1099     REGEXP *rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1100     SV * ret;
1101     dVAR; 
1102     dXSARGS;
1103
1104     if (items != 0)
1105        Perl_croak(aTHX_ "Usage: %s(%s)", "re::regnames_count", "");
1106
1107     SP -= items;
1108
1109     if (!rx)
1110         XSRETURN_UNDEF;
1111
1112     ret = CALLREG_NAMED_BUFF_COUNT(rx);
1113
1114     SPAGAIN;
1115
1116     if (ret) {
1117         XPUSHs(ret);
1118         PUTBACK;
1119         return;
1120     } else {
1121         XSRETURN_UNDEF;
1122     }
1123 }
1124
1125 XS(XS_re_regname)
1126 {
1127     dVAR;
1128     dXSARGS;
1129     REGEXP * rx;
1130     U32 flags;
1131     SV * ret;
1132
1133     if (items < 1 || items > 2)
1134         Perl_croak(aTHX_ "Usage: %s(%s)", "re::regname", "name[, all ]");
1135
1136     SP -= items;
1137
1138     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1139
1140     if (!rx)
1141         XSRETURN_UNDEF;
1142
1143     if (items == 2 && SvTRUE(ST(1))) {
1144         flags = RXf_HASH_ALL;
1145     } else {
1146         flags = RXf_HASH_ONE;
1147     }
1148     ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(0), (flags | RXf_HASH_REGNAME));
1149
1150     if (ret) {
1151         if (SvROK(ret))
1152             XPUSHs(ret);
1153         else
1154             XPUSHs(SvREFCNT_inc(ret));
1155         XSRETURN(1);
1156     }
1157     XSRETURN_UNDEF;    
1158 }
1159
1160
1161 XS(XS_re_regnames)
1162 {
1163     dVAR;
1164     dXSARGS;
1165     REGEXP * rx;
1166     U32 flags;
1167     SV *ret;
1168     AV *av;
1169     I32 length;
1170     I32 i;
1171     SV **entry;
1172
1173     if (items > 1)
1174         Perl_croak(aTHX_ "Usage: %s(%s)", "re::regnames", "[all]");
1175
1176     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1177
1178     if (!rx)
1179         XSRETURN_UNDEF;
1180
1181     if (items == 1 && SvTRUE(ST(0))) {
1182         flags = RXf_HASH_ALL;
1183     } else {
1184         flags = RXf_HASH_ONE;
1185     }
1186
1187     SP -= items;
1188
1189     ret = CALLREG_NAMED_BUFF_ALL(rx, (flags | RXf_HASH_REGNAMES));
1190
1191     SPAGAIN;
1192
1193     SP -= items;
1194
1195     if (!ret)
1196         XSRETURN_UNDEF;
1197
1198     av = (AV*)SvRV(ret);
1199     length = av_len(av);
1200
1201     for (i = 0; i <= length; i++) {
1202         entry = av_fetch(av, i, FALSE);
1203         
1204         if (!entry)
1205             Perl_croak(aTHX_ "NULL array element in re::regnames()");
1206
1207         XPUSHs(*entry);
1208     }
1209     PUTBACK;
1210     return;
1211 }
1212
1213 XS(XS_Tie_Hash_NamedCapture_FETCH)
1214 {
1215     dVAR;
1216     dXSARGS;
1217     REGEXP * rx;
1218     U32 flags;
1219     SV * ret;
1220
1221     if (items != 2)
1222         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::STORE($key, $flags)");
1223
1224     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1225
1226     if (!rx)
1227         XSRETURN_UNDEF;
1228
1229     SP -= items;
1230
1231     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1232     ret = CALLREG_NAMED_BUFF_FETCH(rx, ST(1), flags);
1233
1234     SPAGAIN;
1235
1236     if (ret) {
1237         if (SvROK(ret))
1238             XPUSHs(ret);
1239         else
1240             XPUSHs(SvREFCNT_inc(ret));
1241         PUTBACK;
1242         return;
1243     }
1244     XSRETURN_UNDEF;
1245 }
1246
1247 XS(XS_Tie_Hash_NamedCapture_STORE)
1248 {
1249     dVAR;
1250     dXSARGS;
1251     REGEXP * rx;
1252     U32 flags;
1253
1254     if (items != 3)
1255         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::STORE($key, $value, $flags)");
1256
1257     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1258
1259     if (!rx) {
1260         if (!PL_localizing)
1261             Perl_croak(aTHX_ PL_no_modify);
1262         else
1263             XSRETURN_UNDEF;
1264     }
1265
1266     SP -= items;
1267
1268     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1269     CALLREG_NAMED_BUFF_STORE(rx,ST(1), ST(2), flags);
1270 }
1271
1272 XS(XS_Tie_Hash_NamedCapture_DELETE)
1273 {
1274     dVAR;
1275     dXSARGS;
1276     REGEXP * rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1277     U32 flags;
1278
1279     if (items != 2)
1280         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::DELETE($key, $flags)");
1281
1282     if (!rx)
1283         Perl_croak(aTHX_ PL_no_modify);
1284
1285     SP -= items;
1286
1287     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1288     CALLREG_NAMED_BUFF_DELETE(rx, ST(1), flags);
1289 }
1290
1291 XS(XS_Tie_Hash_NamedCapture_CLEAR)
1292 {
1293     dVAR;
1294     dXSARGS;
1295     REGEXP * rx;
1296     U32 flags;
1297
1298     if (items != 1)
1299         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::CLEAR($flags)");
1300
1301     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1302
1303     if (!rx)
1304         Perl_croak(aTHX_ PL_no_modify);
1305
1306     SP -= items;
1307
1308     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1309     CALLREG_NAMED_BUFF_CLEAR(rx, flags);
1310 }
1311
1312 XS(XS_Tie_Hash_NamedCapture_EXISTS)
1313 {
1314     dVAR;
1315     dXSARGS;
1316     REGEXP * rx;
1317     U32 flags;
1318     SV * ret;
1319
1320     if (items != 2)
1321         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::EXISTS($key, $flags)");
1322
1323     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1324
1325     if (!rx)
1326         XSRETURN_UNDEF;
1327
1328     SP -= items;
1329
1330     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1331     ret = CALLREG_NAMED_BUFF_EXISTS(rx, ST(1), flags);
1332
1333     SPAGAIN;
1334
1335         XPUSHs(ret);
1336         PUTBACK;
1337         return;
1338 }
1339
1340 XS(XS_Tie_Hash_NamedCapture_FIRSTKEY)
1341 {
1342     dVAR;
1343     dXSARGS;
1344     REGEXP * rx;
1345     U32 flags;
1346     SV * ret;
1347
1348     if (items != 1)
1349         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::FIRSTKEY()");
1350
1351     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1352
1353     if (!rx)
1354         XSRETURN_UNDEF;
1355
1356     SP -= items;
1357
1358     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1359     ret = CALLREG_NAMED_BUFF_FIRSTKEY(rx, flags);
1360
1361     SPAGAIN;
1362
1363     if (ret) {
1364         XPUSHs(SvREFCNT_inc(ret));
1365         PUTBACK;
1366     } else {
1367         XSRETURN_UNDEF;
1368     }
1369
1370 }
1371
1372 XS(XS_Tie_Hash_NamedCapture_NEXTKEY)
1373 {
1374     dVAR;
1375     dXSARGS;
1376     REGEXP * rx;
1377     U32 flags;
1378     SV * ret;
1379
1380     if (items != 2)
1381         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::NEXTKEY($lastkey)");
1382
1383     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1384
1385     if (!rx)
1386         XSRETURN_UNDEF;
1387
1388     SP -= items;
1389
1390     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1391     ret = CALLREG_NAMED_BUFF_NEXTKEY(rx, ST(1), flags);
1392
1393     SPAGAIN;
1394
1395     if (ret) {
1396         XPUSHs(ret);
1397     } else {
1398         XSRETURN_UNDEF;
1399     }  
1400     PUTBACK;
1401 }
1402
1403 XS(XS_Tie_Hash_NamedCapture_SCALAR)
1404 {
1405     dVAR;
1406     dXSARGS;
1407     REGEXP * rx;
1408     U32 flags;
1409     SV * ret;
1410
1411     if (items != 1)
1412         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::SCALAR()");
1413
1414     rx = PL_curpm ? PM_GETRE(PL_curpm) : NULL;
1415
1416     if (!rx)
1417         XSRETURN_UNDEF;
1418
1419     SP -= items;
1420
1421     flags = (U32)INT2PTR(IV,SvIV(SvRV((SV*)ST(0))));
1422     ret = CALLREG_NAMED_BUFF_SCALAR(rx, flags);
1423
1424     SPAGAIN;
1425
1426     if (ret) {
1427         XPUSHs(ret);
1428         PUTBACK;
1429         return;
1430     } else {
1431         XSRETURN_UNDEF;
1432     }
1433 }
1434
1435 XS(XS_Tie_Hash_NamedCapture_flags)
1436 {
1437     dVAR;
1438     dXSARGS;
1439
1440     if (items != 0)
1441         Perl_croak(aTHX_ "Usage: Tie::Hash::NamedCapture::flags()");
1442
1443         XPUSHs(sv_2mortal(newSVuv(RXf_HASH_ONE)));
1444         XPUSHs(sv_2mortal(newSVuv(RXf_HASH_ALL)));
1445         PUTBACK;
1446         return;
1447 }
1448
1449
1450 /*
1451  * Local variables:
1452  * c-indentation-style: bsd
1453  * c-basic-offset: 4
1454  * indent-tabs-mode: t
1455  * End:
1456  *
1457  * ex: set ts=8 sts=4 sw=4 noet:
1458  */