/* util.c
*
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- * 2000, 2001, 2002, 2003, by Larry Wall and others
+ * 2000, 2001, 2002, 2003, 2004, by Larry Wall and others
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
* not content." --Gandalf
*/
+/* This file contains assorted utility routines.
+ * Which is a polite way of saying any stuff that people couldn't think of
+ * a better place for. Amongst other things, it includes the warning and
+ * dieing stuff, plus wrappers for malloc code.
+ */
+
#include "EXTERN.h"
#define PERL_IN_UTIL_C
#include "perl.h"
#ifndef PERL_MICRO
-#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
#include <signal.h>
-#endif
-
#ifndef SIG_ERR
# define SIG_ERR ((Sighandler_t) -1)
#endif
else if (PL_nomemok)
return Nullch;
else {
- PerlIO_puts(Perl_error_log,PL_no_mem) FLUSH;
+ /* Can't use PerlIO to write as it allocates memory */
+ PerlLIO_write(PerlIO_fileno(Perl_error_log),
+ PL_no_mem, strlen(PL_no_mem));
my_exit(1);
return Nullch;
}
else if (PL_nomemok)
return Nullch;
else {
- PerlIO_puts(Perl_error_log,PL_no_mem) FLUSH;
+ /* Can't use PerlIO to write as it allocates memory */
+ PerlLIO_write(PerlIO_fileno(Perl_error_log),
+ PL_no_mem, strlen(PL_no_mem));
my_exit(1);
return Nullch;
}
else if (PL_nomemok)
return Nullch;
else {
- PerlIO_puts(Perl_error_log,PL_no_mem) FLUSH;
+ /* Can't use PerlIO to write as it allocates memory */
+ PerlLIO_write(PerlIO_fileno(Perl_error_log),
+ PL_no_mem, strlen(PL_no_mem));
my_exit(1);
return Nullch;
}
char *
Perl_savepv(pTHX_ const char *pv)
{
- register char *newaddr = Nullch;
- if (pv) {
- New(902,newaddr,strlen(pv)+1,char);
- (void)strcpy(newaddr,pv);
- }
- return newaddr;
+ register char *newaddr;
+ if (!pv)
+ return Nullch;
+
+ New(902,newaddr,strlen(pv)+1,char);
+ return strcpy(newaddr,pv);
}
/* same thing but with a known length */
New(903,newaddr,len+1,char);
/* Give a meaning to NULL pointer mainly for the use in sv_magic() */
if (pv) {
- Copy(pv,newaddr,len,char); /* might not be null terminated */
- newaddr[len] = '\0'; /* is now */
+ /* might not be null terminated */
+ newaddr[len] = '\0';
+ return CopyD(pv,newaddr,len,char);
}
else {
- Zero(newaddr,len+1,char);
+ return ZeroD(newaddr,len+1,char);
}
- return newaddr;
}
/*
char *
Perl_savesharedpv(pTHX_ const char *pv)
{
- register char *newaddr = Nullch;
- if (pv) {
- newaddr = (char*)PerlMemShared_malloc(strlen(pv)+1);
- (void)strcpy(newaddr,pv);
+ register char *newaddr;
+ if (!pv)
+ return Nullch;
+
+ newaddr = (char*)PerlMemShared_malloc(strlen(pv)+1);
+ if (!newaddr) {
+ PerlLIO_write(PerlIO_fileno(Perl_error_log),
+ PL_no_mem, strlen(PL_no_mem));
+ my_exit(1);
}
- return newaddr;
+ return strcpy(newaddr,pv);
}
}
}
-OP *
-Perl_vdie(pTHX_ const char* pat, va_list *args)
+/* Common code used by vcroak, vdie and vwarner */
+
+void S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8);
+
+char *
+S_vdie_croak_common(pTHX_ const char* pat, va_list* args, STRLEN* msglen,
+ I32* utf8)
{
char *message;
- int was_in_eval = PL_in_eval;
- HV *stash;
- GV *gv;
- CV *cv;
- SV *msv;
- STRLEN msglen;
-
- DEBUG_S(PerlIO_printf(Perl_debug_log,
- "%p: die: curstack = %p, mainstack = %p\n",
- thr, PL_curstack, PL_mainstack));
if (pat) {
- msv = vmess(pat, args);
+ SV *msv = vmess(pat, args);
if (PL_errors && SvCUR(PL_errors)) {
sv_catsv(PL_errors, msv);
- message = SvPV(PL_errors, msglen);
+ message = SvPV(PL_errors, *msglen);
SvCUR_set(PL_errors, 0);
}
else
- message = SvPV(msv,msglen);
+ message = SvPV(msv,*msglen);
+ *utf8 = SvUTF8(msv);
}
else {
message = Nullch;
- msglen = 0;
}
DEBUG_S(PerlIO_printf(Perl_debug_log,
- "%p: die: message = %s\ndiehook = %p\n",
+ "%p: die/croak: message = %s\ndiehook = %p\n",
thr, message, PL_diehook));
if (PL_diehook) {
- /* sv_2cv might call Perl_croak() */
- SV *olddiehook = PL_diehook;
- ENTER;
- SAVESPTR(PL_diehook);
- PL_diehook = Nullsv;
- cv = sv_2cv(olddiehook, &stash, &gv, 0);
- LEAVE;
- if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
- dSP;
- SV *msg;
+ S_vdie_common(aTHX_ message, *msglen, *utf8);
+ }
+ return message;
+}
- ENTER;
- save_re_context();
- if (message) {
- msg = newSVpvn(message, msglen);
- SvREADONLY_on(msg);
- SAVEFREESV(msg);
- }
- else {
- msg = ERRSV;
- }
+void
+S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8)
+{
+ HV *stash;
+ GV *gv;
+ CV *cv;
+ /* sv_2cv might call Perl_croak() */
+ SV *olddiehook = PL_diehook;
+
+ assert(PL_diehook);
+ ENTER;
+ SAVESPTR(PL_diehook);
+ PL_diehook = Nullsv;
+ cv = sv_2cv(olddiehook, &stash, &gv, 0);
+ LEAVE;
+ if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
+ dSP;
+ SV *msg;
- PUSHSTACKi(PERLSI_DIEHOOK);
- PUSHMARK(SP);
- XPUSHs(msg);
- PUTBACK;
- call_sv((SV*)cv, G_DISCARD);
- POPSTACK;
- LEAVE;
+ ENTER;
+ save_re_context();
+ if (message) {
+ msg = newSVpvn(message, msglen);
+ SvFLAGS(msg) |= utf8;
+ SvREADONLY_on(msg);
+ SAVEFREESV(msg);
}
+ else {
+ msg = ERRSV;
+ }
+
+ PUSHSTACKi(PERLSI_DIEHOOK);
+ PUSHMARK(SP);
+ XPUSHs(msg);
+ PUTBACK;
+ call_sv((SV*)cv, G_DISCARD);
+ POPSTACK;
+ LEAVE;
}
+}
+
+OP *
+Perl_vdie(pTHX_ const char* pat, va_list *args)
+{
+ char *message;
+ int was_in_eval = PL_in_eval;
+ STRLEN msglen;
+ I32 utf8 = 0;
+
+ DEBUG_S(PerlIO_printf(Perl_debug_log,
+ "%p: die: curstack = %p, mainstack = %p\n",
+ thr, PL_curstack, PL_mainstack));
+
+ message = S_vdie_croak_common(aTHX_ pat, args, &msglen, &utf8);
PL_restartop = die_where(message, msglen);
+ SvFLAGS(ERRSV) |= utf8;
DEBUG_S(PerlIO_printf(Perl_debug_log,
"%p: die: restartop = %p, was_in_eval = %d, top_env = %p\n",
thr, PL_restartop, was_in_eval, PL_top_env));
Perl_vcroak(pTHX_ const char* pat, va_list *args)
{
char *message;
- HV *stash;
- GV *gv;
- CV *cv;
- SV *msv;
STRLEN msglen;
+ I32 utf8 = 0;
- if (pat) {
- msv = vmess(pat, args);
- if (PL_errors && SvCUR(PL_errors)) {
- sv_catsv(PL_errors, msv);
- message = SvPV(PL_errors, msglen);
- SvCUR_set(PL_errors, 0);
- }
- else
- message = SvPV(msv,msglen);
- }
- else {
- message = Nullch;
- msglen = 0;
- }
-
- DEBUG_S(PerlIO_printf(Perl_debug_log, "croak: 0x%"UVxf" %s",
- PTR2UV(thr), message));
+ message = S_vdie_croak_common(aTHX_ pat, args, &msglen, &utf8);
- if (PL_diehook) {
- /* sv_2cv might call Perl_croak() */
- SV *olddiehook = PL_diehook;
- ENTER;
- SAVESPTR(PL_diehook);
- PL_diehook = Nullsv;
- cv = sv_2cv(olddiehook, &stash, &gv, 0);
- LEAVE;
- if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
- dSP;
- SV *msg;
-
- ENTER;
- save_re_context();
- if (message) {
- msg = newSVpvn(message, msglen);
- SvREADONLY_on(msg);
- SAVEFREESV(msg);
- }
- else {
- msg = ERRSV;
- }
-
- PUSHSTACKi(PERLSI_DIEHOOK);
- PUSHMARK(SP);
- XPUSHs(msg);
- PUTBACK;
- call_sv((SV*)cv, G_DISCARD);
- POPSTACK;
- LEAVE;
- }
- }
if (PL_in_eval) {
PL_restartop = die_where(message, msglen);
+ SvFLAGS(ERRSV) |= utf8;
JMPENV_JUMP(3);
}
else if (!message)
=for apidoc croak
This is the XSUB-writer's interface to Perl's C<die> function.
-Normally use this function the same way you use the C C<printf>
-function. See C<warn>.
+Normally call this function the same way you call the C C<printf>
+function. Calling C<croak> returns control directly to Perl,
+sidestepping the normal C order of execution. See C<warn>.
If you want to throw an exception object, assign the object to
C<$@> and then pass C<Nullch> to croak():
CV *cv;
SV *msv;
STRLEN msglen;
+ I32 utf8 = 0;
msv = vmess(pat, args);
+ utf8 = SvUTF8(msv);
message = SvPV(msv, msglen);
if (PL_warnhook) {
ENTER;
save_re_context();
msg = newSVpvn(message, msglen);
+ SvFLAGS(msg) |= utf8;
SvREADONLY_on(msg);
SAVEFREESV(msg);
/*
=for apidoc warn
-This is the XSUB-writer's interface to Perl's C<warn> function. Use this
-function the same way you use the C C<printf> function. See
-C<croak>.
+This is the XSUB-writer's interface to Perl's C<warn> function. Call this
+function the same way you call the C C<printf> function. See C<croak>.
=cut
*/
void
Perl_vwarner(pTHX_ U32 err, const char* pat, va_list* args)
{
- char *message;
- HV *stash;
- GV *gv;
- CV *cv;
- SV *msv;
- STRLEN msglen;
-
- msv = vmess(pat, args);
- message = SvPV(msv, msglen);
-
if (ckDEAD(err)) {
+ SV *msv = vmess(pat, args);
+ STRLEN msglen;
+ char *message = SvPV(msv, msglen);
+ I32 utf8 = SvUTF8(msv);
+
if (PL_diehook) {
- /* sv_2cv might call Perl_croak() */
- SV *olddiehook = PL_diehook;
- ENTER;
- SAVESPTR(PL_diehook);
- PL_diehook = Nullsv;
- cv = sv_2cv(olddiehook, &stash, &gv, 0);
- LEAVE;
- if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
- dSP;
- SV *msg;
-
- ENTER;
- save_re_context();
- msg = newSVpvn(message, msglen);
- SvREADONLY_on(msg);
- SAVEFREESV(msg);
-
- PUSHSTACKi(PERLSI_DIEHOOK);
- PUSHMARK(sp);
- XPUSHs(msg);
- PUTBACK;
- call_sv((SV*)cv, G_DISCARD);
- POPSTACK;
- LEAVE;
- }
+ assert(message);
+ S_vdie_common(aTHX_ message, msglen, utf8);
}
if (PL_in_eval) {
PL_restartop = die_where(message, msglen);
+ SvFLAGS(ERRSV) |= utf8;
JMPENV_JUMP(3);
}
write_to_stderr(message, msglen);
my_failure_exit();
}
else {
- if (PL_warnhook) {
- /* sv_2cv might call Perl_warn() */
- SV *oldwarnhook = PL_warnhook;
- ENTER;
- SAVESPTR(PL_warnhook);
- PL_warnhook = Nullsv;
- cv = sv_2cv(oldwarnhook, &stash, &gv, 0);
- LEAVE;
- if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
- dSP;
- SV *msg;
-
- ENTER;
- save_re_context();
- msg = newSVpvn(message, msglen);
- SvREADONLY_on(msg);
- SAVEFREESV(msg);
-
- PUSHSTACKi(PERLSI_WARNHOOK);
- PUSHMARK(sp);
- XPUSHs(msg);
- PUTBACK;
- call_sv((SV*)cv, G_DISCARD);
- POPSTACK;
- LEAVE;
- return;
- }
- }
- write_to_stderr(message, msglen);
+ Perl_vwarn(aTHX_ pat, args);
}
}
* -DWS
*/
-#define HTOV(name,type) \
+#define HTOLE(name,type) \
+ type \
+ name (register type n) \
+ { \
+ union { \
+ type value; \
+ char c[sizeof(type)]; \
+ } u; \
+ register I32 i; \
+ register I32 s = 0; \
+ for (i = 0; i < sizeof(u.c); i++, s += 8) { \
+ u.c[i] = (n >> s) & 0xFF; \
+ } \
+ return u.value; \
+ }
+
+#define LETOH(name,type) \
+ type \
+ name (register type n) \
+ { \
+ union { \
+ type value; \
+ char c[sizeof(type)]; \
+ } u; \
+ register I32 i; \
+ register I32 s = 0; \
+ u.value = n; \
+ n = 0; \
+ for (i = 0; i < sizeof(u.c); i++, s += 8) { \
+ n |= ((type)(u.c[i] & 0xFF)) << s; \
+ } \
+ return n; \
+ }
+
+/*
+ * Big-endian byte order functions.
+ */
+
+#define HTOBE(name,type) \
type \
name (register type n) \
{ \
char c[sizeof(type)]; \
} u; \
register I32 i; \
- register I32 s; \
- for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) { \
+ register I32 s = 8*(sizeof(u.c)-1); \
+ for (i = 0; i < sizeof(u.c); i++, s -= 8) { \
u.c[i] = (n >> s) & 0xFF; \
} \
return u.value; \
}
-#define VTOH(name,type) \
+#define BETOH(name,type) \
type \
name (register type n) \
{ \
char c[sizeof(type)]; \
} u; \
register I32 i; \
- register I32 s; \
+ register I32 s = 8*(sizeof(u.c)-1); \
u.value = n; \
n = 0; \
- for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) { \
- n += (u.c[i] & 0xFF) << s; \
+ for (i = 0; i < sizeof(u.c); i++, s -= 8) { \
+ n |= ((type)(u.c[i] & 0xFF)) << s; \
} \
return n; \
}
+/*
+ * If we just can't do it...
+ */
+
+#define NOT_AVAIL(name,type) \
+ type \
+ name (register type n) \
+ { \
+ Perl_croak_nocontext(#name "() not available"); \
+ return n; /* not reached */ \
+ }
+
+
#if defined(HAS_HTOVS) && !defined(htovs)
-HTOV(htovs,short)
+HTOLE(htovs,short)
#endif
#if defined(HAS_HTOVL) && !defined(htovl)
-HTOV(htovl,long)
+HTOLE(htovl,long)
#endif
#if defined(HAS_VTOHS) && !defined(vtohs)
-VTOH(vtohs,short)
+LETOH(vtohs,short)
#endif
#if defined(HAS_VTOHL) && !defined(vtohl)
-VTOH(vtohl,long)
+LETOH(vtohl,long)
+#endif
+
+#ifdef PERL_NEED_MY_HTOLE16
+# if U16SIZE == 2
+HTOLE(Perl_my_htole16,U16)
+# else
+NOT_AVAIL(Perl_my_htole16,U16)
+# endif
+#endif
+#ifdef PERL_NEED_MY_LETOH16
+# if U16SIZE == 2
+LETOH(Perl_my_letoh16,U16)
+# else
+NOT_AVAIL(Perl_my_letoh16,U16)
+# endif
+#endif
+#ifdef PERL_NEED_MY_HTOBE16
+# if U16SIZE == 2
+HTOBE(Perl_my_htobe16,U16)
+# else
+NOT_AVAIL(Perl_my_htobe16,U16)
+# endif
+#endif
+#ifdef PERL_NEED_MY_BETOH16
+# if U16SIZE == 2
+BETOH(Perl_my_betoh16,U16)
+# else
+NOT_AVAIL(Perl_my_betoh16,U16)
+# endif
+#endif
+
+#ifdef PERL_NEED_MY_HTOLE32
+# if U32SIZE == 4
+HTOLE(Perl_my_htole32,U32)
+# else
+NOT_AVAIL(Perl_my_htole32,U32)
+# endif
+#endif
+#ifdef PERL_NEED_MY_LETOH32
+# if U32SIZE == 4
+LETOH(Perl_my_letoh32,U32)
+# else
+NOT_AVAIL(Perl_my_letoh32,U32)
+# endif
+#endif
+#ifdef PERL_NEED_MY_HTOBE32
+# if U32SIZE == 4
+HTOBE(Perl_my_htobe32,U32)
+# else
+NOT_AVAIL(Perl_my_htobe32,U32)
+# endif
+#endif
+#ifdef PERL_NEED_MY_BETOH32
+# if U32SIZE == 4
+BETOH(Perl_my_betoh32,U32)
+# else
+NOT_AVAIL(Perl_my_betoh32,U32)
+# endif
#endif
+#ifdef PERL_NEED_MY_HTOLE64
+# if U64SIZE == 8
+HTOLE(Perl_my_htole64,U64)
+# else
+NOT_AVAIL(Perl_my_htole64,U64)
+# endif
+#endif
+#ifdef PERL_NEED_MY_LETOH64
+# if U64SIZE == 8
+LETOH(Perl_my_letoh64,U64)
+# else
+NOT_AVAIL(Perl_my_letoh64,U64)
+# endif
+#endif
+#ifdef PERL_NEED_MY_HTOBE64
+# if U64SIZE == 8
+HTOBE(Perl_my_htobe64,U64)
+# else
+NOT_AVAIL(Perl_my_htobe64,U64)
+# endif
+#endif
+#ifdef PERL_NEED_MY_BETOH64
+# if U64SIZE == 8
+BETOH(Perl_my_betoh64,U64)
+# else
+NOT_AVAIL(Perl_my_betoh64,U64)
+# endif
+#endif
+
+#ifdef PERL_NEED_MY_HTOLES
+HTOLE(Perl_my_htoles,short)
+#endif
+#ifdef PERL_NEED_MY_LETOHS
+LETOH(Perl_my_letohs,short)
+#endif
+#ifdef PERL_NEED_MY_HTOBES
+HTOBE(Perl_my_htobes,short)
+#endif
+#ifdef PERL_NEED_MY_BETOHS
+BETOH(Perl_my_betohs,short)
+#endif
+
+#ifdef PERL_NEED_MY_HTOLEI
+HTOLE(Perl_my_htolei,int)
+#endif
+#ifdef PERL_NEED_MY_LETOHI
+LETOH(Perl_my_letohi,int)
+#endif
+#ifdef PERL_NEED_MY_HTOBEI
+HTOBE(Perl_my_htobei,int)
+#endif
+#ifdef PERL_NEED_MY_BETOHI
+BETOH(Perl_my_betohi,int)
+#endif
+
+#ifdef PERL_NEED_MY_HTOLEL
+HTOLE(Perl_my_htolel,long)
+#endif
+#ifdef PERL_NEED_MY_LETOHL
+LETOH(Perl_my_letohl,long)
+#endif
+#ifdef PERL_NEED_MY_HTOBEL
+HTOBE(Perl_my_htobel,long)
+#endif
+#ifdef PERL_NEED_MY_BETOHL
+BETOH(Perl_my_betohl,long)
+#endif
+
+void
+Perl_my_swabn(void *ptr, int n)
+{
+ register char *s = (char *)ptr;
+ register char *e = s + (n-1);
+ register char tc;
+
+ for (n /= 2; n > 0; s++, e--, n--) {
+ tc = *s;
+ *s = *e;
+ *e = tc;
+ }
+}
+
PerlIO *
Perl_my_popen_list(pTHX_ char *mode, int n, SV **args)
{
#if defined(HAS_FCNTL) && defined(F_SETFD)
/* Close error pipe automatically if exec works */
fcntl(pp[1], F_SETFD, FD_CLOEXEC);
-#else
- PerlLIO_close(pp[1]); /* Do as best as we can: pretend success. */
#endif
}
/* Now dup our end of _the_ pipe to right position */
PerlLIO_close(pp[0]);
#if defined(HAS_FCNTL) && defined(F_SETFD)
fcntl(pp[1], F_SETFD, FD_CLOEXEC);
-#else
- PerlLIO_close(pp[1]); /* Do as best as we can: pretend success. */
#endif
}
if (p[THIS] != (*mode == 'r')) {
Function must be called with an already existing SV like
- sv = NEWSV(92,0);
- s = scan_version(s,sv);
+ sv = newSV(0);
+ s = scan_version(s,SV *sv, bool qv);
Performs some preprocessing to the string to ensure that
it has the correct characteristics of a version. Flags the
object if it contains an underscore (which denotes this
-is a beta version).
+is a alpha version). The boolean qv denotes that the version
+should be interpreted as if it had multiple decimals, even if
+it doesn't.
=cut
*/
char *
-Perl_scan_version(pTHX_ char *s, SV *rv)
+Perl_scan_version(pTHX_ char *s, SV *rv, bool qv)
{
const char *start = s;
char *pos = s;
bool saw_under = 0;
SV* sv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
(void)sv_upgrade(sv, SVt_PVAV); /* needs to be an AV type */
+ AvREAL_on((AV*)sv);
/* pre-scan the imput string to check for decimals */
while ( *pos == '.' || *pos == '_' || isDIGIT(*pos) )
}
pos = s;
- if (*pos == 'v') pos++; /* get past 'v' */
+ if (*pos == 'v') {
+ pos++; /* get past 'v' */
+ qv = 1; /* force quoted version processing */
+ }
while (isDIGIT(*pos))
pos++;
if (!isALPHA(*pos)) {
I32 mult = 1;
I32 orev;
if ( s < pos && s > start && *(s-1) == '_' ) {
- mult *= -1; /* beta version */
+ mult *= -1; /* alpha version */
}
/* the following if() will only be true after the decimal
* point of a version originally created with a bare
* floating point number, i.e. not quoted in any way
*/
- if ( s > start+1 && saw_period == 1 && !saw_under ) {
- mult = 100;
+ if ( !qv && s > start+1 && saw_period == 1 ) {
+ mult *= 100;
while ( s < end ) {
orev = rev;
rev += (*s - '0') * mult;
break;
}
while ( isDIGIT(*pos) ) {
- if ( !saw_under && saw_period == 1 && pos-s == 3 )
+ if ( saw_period == 1 && pos-s == 3 )
break;
pos++;
}
}
}
+ if ( qv ) { /* quoted versions always become full version objects */
+ I32 len = av_len((AV *)sv);
+ /* This for loop appears to trigger a compiler bug on OS X, as it
+ loops infinitely. Yes, len is negative. No, it makes no sense.
+ Compiler in question is:
+ gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)
+ for ( len = 2 - len; len > 0; len-- )
+ av_push((AV *)sv, newSViv(0));
+ */
+ len = 2 - len;
+ while (len-- > 0)
+ av_push((AV *)sv, newSViv(0));
+ }
return s;
}
Perl_new_version(pTHX_ SV *ver)
{
SV *rv = newSV(0);
- char *version;
- if ( SvNOK(ver) ) /* may get too much accuracy */
+ if ( sv_derived_from(ver,"version") ) /* can just copy directly */
{
- char tbuf[64];
- sprintf(tbuf,"%.9"NVgf, SvNVX(ver));
- version = savepv(tbuf);
+ I32 key;
+ AV *av = (AV *)SvRV(ver);
+ SV* sv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
+ (void)sv_upgrade(sv, SVt_PVAV); /* needs to be an AV type */
+ AvREAL_on((AV*)sv);
+ for ( key = 0; key <= av_len(av); key++ )
+ {
+ I32 rev = SvIV(*av_fetch(av, key, FALSE));
+ av_push((AV *)sv, newSViv(rev));
+ }
+ return rv;
}
#ifdef SvVOK
- else if ( SvVOK(ver) ) { /* already a v-string */
+ if ( SvVOK(ver) ) { /* already a v-string */
+ char *version;
MAGIC* mg = mg_find(ver,PERL_MAGIC_vstring);
version = savepvn( (const char*)mg->mg_ptr,mg->mg_len );
+ sv_setpv(rv,version);
+ Safefree(version);
}
+ else {
#endif
- else /* must be a string or something like a string */
- {
- version = (char *)SvPV(ver,PL_na);
+ sv_setsv(rv,ver); /* make a duplicate */
+#ifdef SvVOK
}
- version = scan_version(version,rv);
+#endif
+ upg_version(rv);
return rv;
}
SV *
Perl_upg_version(pTHX_ SV *ver)
{
- char *version = savepvn(SvPVX(ver),SvCUR(ver));
+ char *version;
+ bool qv = 0;
+
+ if ( SvNOK(ver) ) /* may get too much accuracy */
+ {
+ char tbuf[64];
+ sprintf(tbuf,"%.9"NVgf, SvNVX(ver));
+ version = savepv(tbuf);
+ }
#ifdef SvVOK
- if ( SvVOK(ver) ) { /* already a v-string */
+ else if ( SvVOK(ver) ) { /* already a v-string */
MAGIC* mg = mg_find(ver,PERL_MAGIC_vstring);
version = savepvn( (const char*)mg->mg_ptr,mg->mg_len );
+ qv = 1;
}
#endif
- version = scan_version(version,ver);
+ else /* must be a string or something like a string */
+ {
+ STRLEN n_a;
+ version = savepv(SvPV(ver,n_a));
+ }
+ (void)scan_version(version, ver, qv);
+ Safefree(version);
return ver;
}
Perl_vnumify(pTHX_ SV *vs)
{
I32 i, len, digit;
- SV *sv = NEWSV(92,0);
+ SV *sv = newSV(0);
if ( SvROK(vs) )
vs = SvRV(vs);
len = av_len((AV *)vs);
return sv;
}
digit = SvIVX(*av_fetch((AV *)vs, 0, 0));
- Perl_sv_setpvf(aTHX_ sv,"%d.", PERL_ABS(digit));
- for ( i = 1 ; i <= len ; i++ )
+ Perl_sv_setpvf(aTHX_ sv,"%d.", (int)PERL_ABS(digit));
+ for ( i = 1 ; i < len ; i++ )
{
digit = SvIVX(*av_fetch((AV *)vs, i, 0));
- Perl_sv_catpvf(aTHX_ sv,"%03d", PERL_ABS(digit));
+ Perl_sv_catpvf(aTHX_ sv,"%03d", (int)PERL_ABS(digit));
}
- if ( len == 0 )
+
+ if ( len > 0 )
+ {
+ digit = SvIVX(*av_fetch((AV *)vs, len, 0));
+ if ( (int)PERL_ABS(digit) != 0 || len == 1 )
+ {
+ if ( digit < 0 ) /* alpha version */
+ Perl_sv_catpv(aTHX_ sv,"_");
+ /* Don't display additional trailing zeros */
+ Perl_sv_catpvf(aTHX_ sv,"%03d", (int)PERL_ABS(digit));
+ }
+ }
+ else /* len == 0 */
+ {
Perl_sv_catpv(aTHX_ sv,"000");
- sv_setnv(sv, SvNV(sv));
+ }
return sv;
}
/*
-=for apidoc vstringify
+=for apidoc vnormal
Accepts a version object and returns the normalized string
representation. Call like:
- sv = vstringify(rv);
+ sv = vnormal(rv);
NOTE: you can pass either the object directly or the SV
contained within the RV.
*/
SV *
-Perl_vstringify(pTHX_ SV *vs)
+Perl_vnormal(pTHX_ SV *vs)
{
I32 i, len, digit;
- SV *sv = NEWSV(92,0);
+ SV *sv = newSV(0);
if ( SvROK(vs) )
vs = SvRV(vs);
len = av_len((AV *)vs);
else
Perl_sv_catpvf(aTHX_ sv,".%"IVdf,(IV)digit);
}
- if ( len == 0 )
- Perl_sv_catpv(aTHX_ sv,".0");
+
+ if ( len <= 2 ) { /* short version, must be at least three */
+ for ( len = 2 - len; len != 0; len-- )
+ Perl_sv_catpv(aTHX_ sv,".0");
+ }
+
return sv;
}
/*
+=for apidoc vstringify
+
+In order to maintain maximum compatibility with earlier versions
+of Perl, this function will return either the floating point
+notation or the multiple dotted notation, depending on whether
+the original version contained 1 or more dots, respectively
+
+=cut
+*/
+
+SV *
+Perl_vstringify(pTHX_ SV *vs)
+{
+ I32 len, digit;
+ if ( SvROK(vs) )
+ vs = SvRV(vs);
+ len = av_len((AV *)vs);
+ digit = SvIVX(*av_fetch((AV *)vs, len, 0));
+
+ if ( len < 2 || ( len == 2 && digit < 0 ) )
+ return vnumify(vs);
+ else
+ return vnormal(vs);
+}
+
+/*
=for apidoc vcmp
Version object aware cmp. Both operands must already have been
{
I32 left = SvIV(*av_fetch((AV *)lsv,i,0));
I32 right = SvIV(*av_fetch((AV *)rsv,i,0));
- bool lbeta = left < 0 ? 1 : 0;
- bool rbeta = right < 0 ? 1 : 0;
- left = PERL_ABS(left);
- right = PERL_ABS(right);
- if ( left < right || (left == right && lbeta && !rbeta) )
+ bool lalpha = left < 0 ? 1 : 0;
+ bool ralpha = right < 0 ? 1 : 0;
+ left = abs(left);
+ right = abs(right);
+ if ( left < right || (left == right && lalpha && !ralpha) )
retval = -1;
- if ( left > right || (left == right && rbeta && !lbeta) )
+ if ( left > right || (left == right && ralpha && !lalpha) )
retval = +1;
i++;
}
- if ( l != r && retval == 0 ) /* possible match except for trailing 0 */
+ if ( l != r && retval == 0 ) /* possible match except for trailing 0's */
{
- if ( !( l < r && r-l == 1 && SvIV(*av_fetch((AV *)rsv,r,0)) == 0 ) &&
- !( l-r == 1 && SvIV(*av_fetch((AV *)lsv,l,0)) == 0 ) )
+ if ( l < r )
{
- retval = l < r ? -1 : +1; /* not a match after all */
+ while ( i <= r && retval == 0 )
+ {
+ if ( SvIV(*av_fetch((AV *)rsv,i,0)) != 0 )
+ retval = -1; /* not a match after all */
+ i++;
+ }
+ }
+ else
+ {
+ while ( i <= l && retval == 0 )
+ {
+ if ( SvIV(*av_fetch((AV *)lsv,i,0)) != 0 )
+ retval = +1; /* not a match after all */
+ i++;
+ }
}
}
return retval;
{
/* Compute a random seed */
(void)seedDrand01((Rand_seed_t)seed());
- PL_srand_called = TRUE;
myseed = (UV)(Drand01() * (NV)UV_MAX);
#if RANDBITS < (UVSIZE * 8)
/* Since there are not enough randbits to to reach all
myseed +=
(UV)(Drand01() * (NV)((1 << ((UVSIZE * 8 - RANDBITS))) - 1));
#endif /* RANDBITS < (UVSIZE * 8) */
+ if (myseed == 0) { /* Superparanoia. */
+ myseed = (UV)(Drand01() * (NV)UV_MAX); /* One more chance. */
+ if (myseed == 0)
+ Perl_croak(aTHX_ "Your random numbers are not that random");
+ }
}
- PL_hash_seed_set = TRUE;
+ PL_rehash_seed_set = TRUE;
return myseed;
}