1 /* This file is part of the "version" CPAN distribution. Please avoid
2 editing it in the perl core. */
5 # define VXS_CLASS "version"
6 # define VXSp(name) XS_##name
8 # define VXS_CLASS "version::vxs"
9 # define VXSp(name) VXS_##name
11 #define VXS(name) XS(VXSp(name))
13 #ifdef VXS_XSUB_DETAILS
15 {"UNIVERSAL::VERSION", XS_UNIVERSAL_VERSION, NULL},
17 {VXS_CLASS "::_VERSION", VXS_UNIVERSAL_VERSION, NULL},
19 {VXS_CLASS "::()", VXSp(version_noop), NULL},
20 {VXS_CLASS "::new", VXSp(version_new), NULL},
21 {VXS_CLASS "::parse", VXSp(version_new), NULL},
22 {VXS_CLASS "::(\"\"", VXSp(version_stringify), NULL},
23 {VXS_CLASS "::stringify", VXSp(version_stringify), NULL},
24 {VXS_CLASS "::(0+", VXSp(version_numify), NULL},
25 {VXS_CLASS "::numify", VXSp(version_numify), NULL},
26 {VXS_CLASS "::normal", VXSp(version_normal), NULL},
27 {VXS_CLASS "::(cmp", VXSp(version_vcmp), NULL},
28 {VXS_CLASS "::(<=>", VXSp(version_vcmp), NULL},
30 {VXS_CLASS "::vcmp", XS_version_vcmp, NULL},
32 {VXS_CLASS "::VCMP", VXS_version_vcmp, NULL},
34 {VXS_CLASS "::(bool", VXSp(version_boolean), NULL},
35 {VXS_CLASS "::boolean", VXSp(version_boolean), NULL},
36 {VXS_CLASS "::(+", VXSp(version_noop), NULL},
37 {VXS_CLASS "::(-", VXSp(version_noop), NULL},
38 {VXS_CLASS "::(*", VXSp(version_noop), NULL},
39 {VXS_CLASS "::(/", VXSp(version_noop), NULL},
40 {VXS_CLASS "::(+=", VXSp(version_noop), NULL},
41 {VXS_CLASS "::(-=", VXSp(version_noop), NULL},
42 {VXS_CLASS "::(*=", VXSp(version_noop), NULL},
43 {VXS_CLASS "::(/=", VXSp(version_noop), NULL},
44 {VXS_CLASS "::(abs", VXSp(version_noop), NULL},
45 {VXS_CLASS "::(nomethod", VXSp(version_noop), NULL},
46 {VXS_CLASS "::noop", VXSp(version_noop), NULL},
47 {VXS_CLASS "::is_alpha", VXSp(version_is_alpha), NULL},
48 {VXS_CLASS "::qv", VXSp(version_qv), NULL},
49 {VXS_CLASS "::declare", VXSp(version_qv), NULL},
50 {VXS_CLASS "::is_qv", VXSp(version_is_qv), NULL},
60 # define HEKfARG(arg) ((void*)(sv_2mortal(newSVhek(arg))))
65 # define HvNAME_HEK HvNAME_get
66 # define HEKfARG(arg) arg
70 VXS(UNIVERSAL_VERSION)
83 Perl_croak(aTHX_ "Usage: UNIVERSAL::VERSION(sv, ...)");
90 Perl_croak(aTHX_ "Cannot find version of an unblessed reference");
94 pkg = gv_stashsv(sv, FALSE);
97 gvp = pkg ? (GV**)hv_fetchs(pkg,"VERSION",FALSE) : (GV**)NULL;
99 if (gvp && isGV(gv = *gvp) && (sv = GvSV(gv)) && SvOK(sv)) {
100 sv = sv_mortalcopy(sv);
101 if ( ! ISA_CLASS_OBJ(sv, "version::vxs"))
102 UPG_VERSION(sv, FALSE);
106 sv = ret = &PL_sv_undef;
115 const HVNAME* const name = HvNAME_HEK(pkg);
116 #if PERL_VERSION == 5
117 Perl_croak(aTHX_ "%s version %s required--this is only version ",
118 name, SvPVx_nolen_const(req));
121 "%"HEKf" does not define $%"HEKf
122 "::VERSION--version check failed",
123 HEKfARG(name), HEKfARG(name));
127 #if PERL_VERSION >= 8
129 "%"SVf" defines neither package nor VERSION--version check failed",
132 Perl_croak(aTHX_ "%s does not define $%s::VERSION--version check failed",
133 SvPVx_nolen_const(ST(0)),
134 SvPVx_nolen_const(ST(0)) );
139 if ( ! ISA_CLASS_OBJ(req, "version")) {
140 /* req may very well be R/O, so create a new object */
141 req = sv_2mortal( NEW_VERSION(req) );
144 if ( VCMP( req, sv ) > 0 ) {
145 if ( hv_exists(MUTABLE_HV(SvRV(req)), "qv", 2 ) ) {
150 req = VSTRINGIFY(req);
153 Perl_croak(aTHX_ "%"HEKf" version %"SVf" required--"
154 "this is only version %"SVf"", HEKfARG(HvNAME_HEK(pkg)),
155 SVfARG(sv_2mortal(req)),
156 SVfARG(sv_2mortal(sv)));
161 /* if the package's $VERSION is not undef, it is upgraded to be a version object */
162 if (ISA_CLASS_OBJ(sv, "version")) {
163 ST(0) = sv_2mortal(VSTRINGIFY(sv));
176 SV *vs = items ? ST(1) : &PL_sv_undef;
178 const char * classname = "";
183 if (items > 3 || items == 0)
184 Perl_croak(aTHX_ "Usage: version::new(class, version)");
186 /* Just in case this is something like a tied hash */
189 if ( items == 1 || ! SvOK(vs) ) { /* no param or explicit undef */
190 /* create empty object */
192 sv_setpvs(vs,"undef");
194 else if (items == 3 ) {
196 #if PERL_VERSION == 5
197 sv_setpvf(vs,"v%s",SvPV_nolen_const(ST(2)));
199 Perl_sv_setpvf(aTHX_ vs,"v%s",SvPV_nolen_const(ST(2)));
202 if ( sv_isobject(ST(0)) ) {
203 /* get the class if called as an object method */
204 const HV * stash = SvSTASH(SvRV(ST(0)));
205 classname = HvNAME_get(stash);
206 len = HvNAMELEN_get(stash);
208 flags = HvNAMEUTF8(stash) ? SVf_UTF8 : 0;
212 classname = SvPV(ST(0), len);
213 flags = SvUTF8(ST(0));
216 rv = NEW_VERSION(vs);
217 if ( len != sizeof(VXS_CLASS)-1
218 || strcmp(classname,VXS_CLASS) != 0 ) /* inherited new() */
219 #if PERL_VERSION == 5
220 sv_bless(rv, gv_stashpv((char *)classname, GV_ADD));
222 sv_bless(rv, gv_stashpvn(classname, len, GV_ADD | flags));
230 #define VTYPECHECK(var, val, varname) \
232 if (ISA_CLASS_OBJ(val, "version")) { \
236 Perl_croak(aTHX_ varname " is not of type version"); \
239 VXS(version_stringify)
244 croak_xs_usage(cv, "lobj, ...");
248 VTYPECHECK(lobj, ST(0), "lobj");
250 mPUSHs(VSTRINGIFY(lobj));
262 croak_xs_usage(cv, "lobj, ...");
266 VTYPECHECK(lobj, ST(0), "lobj");
267 mPUSHs(VNUMIFY(lobj));
278 croak_xs_usage(cv, "ver");
282 VTYPECHECK(ver, ST(0), "ver");
284 mPUSHs(VNORMAL(ver));
296 croak_xs_usage(cv, "lobj, ...");
300 VTYPECHECK(lobj, ST(0), "lobj");
305 const IV swap = (IV)SvIV(ST(2));
307 if ( !ISA_CLASS_OBJ(robj, "version::vxs") )
309 robj = NEW_VERSION(SvOK(robj) ? robj : newSVpvs_flags("0", SVs_TEMP));
316 rs = newSViv(VCMP(rvs,lobj));
320 rs = newSViv(VCMP(lobj,rvs));
337 croak_xs_usage(cv, "lobj, ...");
339 VTYPECHECK(lobj, ST(0), "lobj");
343 sv_2mortal(NEW_VERSION(
344 sv_2mortal(newSVpvs("0"))
359 croak_xs_usage(cv, "lobj, ...");
360 if (ISA_CLASS_OBJ(ST(0), "version"))
361 Perl_croak(aTHX_ "operation not supported with version object");
363 Perl_croak(aTHX_ "lobj is not of type version");
367 VXS(version_is_alpha)
372 croak_xs_usage(cv, "lobj");
376 VTYPECHECK(lobj, ST(0), "lobj");
377 if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "alpha", 5 ) )
396 const char * classname = "";
404 Perl_croak(aTHX_ "Invalid version format (version required)");
406 if ( sv_isobject(ST(0)) ) { /* class called as an object method */
407 const HV * stash = SvSTASH(SvRV(ST(0)));
408 classname = HvNAME_get(stash);
409 len = HvNAMELEN_get(stash);
411 flags = HvNAMEUTF8(stash) ? SVf_UTF8 : 0;
415 classname = SvPV(ST(0), len);
416 flags = SvUTF8(ST(0));
419 if ( !SvVOK(ver) ) { /* not already a v-string */
421 sv_setsv(rv,ver); /* make a duplicate */
422 UPG_VERSION(rv, TRUE);
424 rv = sv_2mortal(NEW_VERSION(ver));
426 if ( items == 2 && (len != 7
427 || strcmp(classname,"version")) ) { /* inherited new() */
428 #if PERL_VERSION == 5
429 sv_bless(rv, gv_stashpv((char *)classname, GV_ADD));
431 sv_bless(rv, gv_stashpvn(classname, len, GV_ADD | flags));
445 croak_xs_usage(cv, "lobj");
449 VTYPECHECK(lobj, ST(0), "lobj");
450 if ( hv_exists(MUTABLE_HV(SvRV(lobj)), "qv", 2 ) )