summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
authorPerl 5 Porters <perl5-porters@africa.nicoh.com>1996-11-19 14:16:00 +1200
committerChip Salzenberg <chip@atlantic.net>1996-11-19 14:16:00 +1200
commit55497cffdd24c959994f9a8ddd56db8ce85e1c5b (patch)
tree444dfb8adc0e5b96d56e0532791122c366f50a3e /pp.c
parentc822f08a5087943f7d9e2c36ce42ea035f03ab97 (diff)
downloadperl-55497cffdd24c959994f9a8ddd56db8ce85e1c5b.tar.gz
[inseparable changes from patch from perl5.003_07 to perl5.003_08]
CORE LANGUAGE CHANGES Subject: Bitwise op sign rationalization From: Chip Salzenberg <chip@atlantic.net> Files: op.c opcode.pl pod/perlop.pod pod/perltoc.pod pp.c pp.h pp_hot.c proto.h sv.c t/op/bop.t Make bitwise ops result in unsigned values, unless C<use integer> is in effect. Includes initial support for UVs. Subject: Defined scoping for C<my> in control structures From: Chip Salzenberg <chip@atlantic.net> Files: op.c perly.c perly.c.diff perly.h perly.y proto.h toke.c Finally defines semantics of "my" in control expressions, like the condition of "if" and "while". In all cases, scope of a "my" var extends to the end of the entire control structure. Also adds new construct "for my", which automatically declares the control variable "my" and limits its scope to the loop. Subject: Fix ++/-- after int conversion (e.g. 'printf "%d"') From: Chip Salzenberg <chip@atlantic.net> Files: pp.c pp_hot.c sv.c This patch makes Perl correctly ignore SvIVX() if either NOK or POK is true, since SvIVX() may be a truncated or overflowed version of the real value. Subject: Make code match Camel II re: functions that use $_ From: Paul Marquess <pmarquess@bfsec.bt.co.uk> Files: opcode.pl Subject: Provide scalar context on left side of "->" From: Chip Salzenberg <chip@atlantic.net> Files: perly.c perly.y Subject: Quote bearword package/handle FOO in "funcname FOO => 'bar'" From: Chip Salzenberg <chip@atlantic.net> Files: toke.c OTHER CORE CHANGES Subject: Warn on overflow of octal and hex integers From: Chip Salzenberg <chip@atlantic.net> Files: proto.h toke.c util.c Subject: If -w active, warn for commas and hashes ('#') in qw() From: Chip Salzenberg <chip@atlantic.net> Files: toke.c Subject: Fixes for pack('w') From: Ulrich Pfeifer <pfeifer@charly.informatik.uni-dortmund.de> Files: pp.c t/op/pack.t Subject: More complete output from sv_dump() From: Gurusamy Sarathy <gsar@engin.umich.edu> Files: sv.c Subject: Major '..' and debugger patches From: Ilya Zakharevich <ilya@math.ohio-state.edu> Files: lib/perl5db.pl op.c pp_ctl.c scope.c scope.h Subject: Fix for formline() From: Gurusamy Sarathy <gsar@engin.umich.edu> Files: global.sym mg.c perl.h pod/perldiag.pod pp_ctl.c proto.h sv.c t/op/write.t Subject: Fix stack botch in untie and binmode From: Gurusamy Sarathy <gsar@engin.umich.edu> Files: pp_sys.c Subject: Complete EMBED, including symbols from interp.sym From: Chip Salzenberg <chip@atlantic.net> Files: MANIFEST embed.pl ext/DynaLoader/dlutils.c ext/SDBM_File/sdbm/sdbm.h global.sym handy.h malloc.c perl.h pp_sys.c proto.h regexec.c toke.c util.c x2p/Makefile.SH x2p/a2p.h x2p/handy.h x2p/util.h New define EMBEDMYMALLOC makes embedding total by avoiding "Mymalloc" etc. Subject: Support old embedding for people who want it From: Chip Salzenberg <chip@atlantic.net> Files: MANIFEST Makefile.SH old_embed.pl old_global.sym PORTABILITY Subject: Miscellaneous VMS fixes From: Charles Bailey <bailey@HMIVAX.HUMGEN.UPENN.EDU> Files: lib/ExtUtils/Liblist.pm lib/ExtUtils/MM_VMS.pm lib/Math/Complex.pm lib/Time/Local.pm lib/timelocal.pl perl.h perl_exp.SH proto.h t/TEST t/io/read.t t/lib/findbin.t t/lib/getopt.t util.c utils/h2xs.PL vms/Makefile vms/config.vms vms/descrip.mms vms/ext/Stdio/Stdio.pm vms/ext/Stdio/Stdio.xs vms/perlvms.pod vms/test.com vms/vms.c Subject: DJGPP patches (MS-DOS) From: "Douglas E. Wegscheid" <wegscd@whirlpool.com> Files: doio.c dosish.h ext/SDBM_File/sdbm/sdbm.c handy.h lib/AutoSplit.pm lib/Cwd.pm lib/File/Find.pm malloc.c perl.c perl.h pp_sys.c proto.h sv.c util.c Subject: Patch to make Perl work under AmigaOS From: "Norbert Pueschel" <pueschel@imsdd.meb.uni-bonn.de> Files: MANIFEST hints/amigaos.sh installman lib/File/Basename.pm lib/File/Find.pm pod/pod2man.PL pp_sys.c util.c
Diffstat (limited to 'pp.c')
-rw-r--r--pp.c292
1 files changed, 215 insertions, 77 deletions
diff --git a/pp.c b/pp.c
index 48e332198b..525e7af802 100644
--- a/pp.c
+++ b/pp.c
@@ -575,14 +575,11 @@ PP(pp_undef)
PP(pp_predec)
{
dSP;
- if (SvIOK(TOPs)) {
- if (SvIVX(TOPs) == IV_MIN) {
- sv_setnv(TOPs, (double)SvIVX(TOPs) - 1.0);
- }
- else {
- --SvIVX(TOPs);
- SvFLAGS(TOPs) &= ~(SVf_NOK|SVf_POK|SVp_NOK|SVp_POK);
- }
+ if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+ SvIVX(TOPs) != IV_MIN)
+ {
+ --SvIVX(TOPs);
+ SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
}
else
sv_dec(TOPs);
@@ -594,14 +591,11 @@ PP(pp_postinc)
{
dSP; dTARGET;
sv_setsv(TARG, TOPs);
- if (SvIOK(TOPs)) {
- if (SvIVX(TOPs) == IV_MAX) {
- sv_setnv(TOPs, (double)SvIVX(TOPs) + 1.0);
- }
- else {
- ++SvIVX(TOPs);
- SvFLAGS(TOPs) &= ~(SVf_NOK|SVf_POK|SVp_NOK|SVp_POK);
- }
+ if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+ SvIVX(TOPs) != IV_MAX)
+ {
+ ++SvIVX(TOPs);
+ SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
}
else
sv_inc(TOPs);
@@ -616,14 +610,11 @@ PP(pp_postdec)
{
dSP; dTARGET;
sv_setsv(TARG, TOPs);
- if (SvIOK(TOPs)) {
- if (SvIVX(TOPs) == IV_MIN) {
- sv_setnv(TOPs, (double)SvIVX(TOPs) - 1.0);
- }
- else {
- --SvIVX(TOPs);
- SvFLAGS(TOPs) &= ~(SVf_NOK|SVf_POK|SVp_NOK|SVp_POK);
- }
+ if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+ SvIVX(TOPs) != IV_MIN)
+ {
+ --SvIVX(TOPs);
+ SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
}
else
sv_dec(TOPs);
@@ -773,9 +764,12 @@ PP(pp_left_shift)
{
dSP; dATARGET; tryAMAGICbin(lshift,opASSIGN);
{
- dPOPTOPiirl;
- SETi( left << right );
- RETURN;
+ dPOPTOPiirl;
+ if (op->op_private & HINT_INTEGER)
+ SETi( left << right );
+ else
+ SETu( (UV)left << right );
+ RETURN;
}
}
@@ -784,7 +778,10 @@ PP(pp_right_shift)
dSP; dATARGET; tryAMAGICbin(rshift,opASSIGN);
{
dPOPTOPiirl;
- SETi( left >> right );
+ if (op->op_private & HINT_INTEGER)
+ SETi( left >> right );
+ else
+ SETu( (UV)left >> right );
RETURN;
}
}
@@ -917,17 +914,17 @@ PP(pp_scmp)
}
}
-PP(pp_bit_and) {
+PP(pp_bit_and)
+{
dSP; dATARGET; tryAMAGICbin(band,opASSIGN);
{
dPOPTOPssrl;
if (SvNIOKp(left) || SvNIOKp(right)) {
- unsigned long value = U_L(SvNV(left));
- value = value & U_L(SvNV(right));
- if ((IV)value == value)
- SETi(value);
+ UV value = SvIV(left) & SvIV(right);
+ if (op->op_private & HINT_INTEGER)
+ SETi( (IV)value );
else
- SETn((double)value);
+ SETu( value );
}
else {
do_vop(op->op_type, TARG, left, right);
@@ -943,12 +940,11 @@ PP(pp_bit_xor)
{
dPOPTOPssrl;
if (SvNIOKp(left) || SvNIOKp(right)) {
- unsigned long value = U_L(SvNV(left));
- value = value ^ U_L(SvNV(right));
- if ((IV)value == value)
- SETi(value);
+ UV value = SvIV(left) ^ SvIV(right);
+ if (op->op_private & HINT_INTEGER)
+ SETi( (IV)value );
else
- SETn((double)value);
+ SETu( value );
}
else {
do_vop(op->op_type, TARG, left, right);
@@ -964,12 +960,11 @@ PP(pp_bit_or)
{
dPOPTOPssrl;
if (SvNIOKp(left) || SvNIOKp(right)) {
- unsigned long value = U_L(SvNV(left));
- value = value | U_L(SvNV(right));
- if ((IV)value == value)
- SETi(value);
+ UV value = SvIV(left) | SvIV(right);
+ if (op->op_private & HINT_INTEGER)
+ SETi( (IV)value );
else
- SETn((double)value);
+ SETu( value );
}
else {
do_vop(op->op_type, TARG, left, right);
@@ -986,7 +981,9 @@ PP(pp_negate)
dTOPss;
if (SvGMAGICAL(sv))
mg_get(sv);
- if (SvNIOKp(sv))
+ if (SvIOKp(sv) && !SvNOKp(sv) && !SvPOKp(sv) && SvIVX(sv) != IV_MIN)
+ SETi(-SvIVX(sv));
+ else if (SvNIOKp(sv))
SETn(-SvNV(sv));
else if (SvPOKp(sv)) {
STRLEN len;
@@ -1023,18 +1020,17 @@ PP(pp_complement)
dSP; dTARGET; tryAMAGICun(compl);
{
dTOPss;
- register I32 anum;
-
if (SvNIOKp(sv)) {
- UV value = ~SvIV(sv);
- if ((IV)value == value)
- SETi(value);
+ UV value = ~(UV)SvIV(sv);
+ if (op->op_private & HINT_INTEGER)
+ SETi( (IV)value );
else
- SETn((double)value);
+ SETu( value );
}
else {
register char *tmps;
register long *tmpl;
+ register I32 anum;
STRLEN len;
SvSetSV(TARG, sv);
@@ -1371,22 +1367,17 @@ PP(pp_hex)
{
dSP; dTARGET;
char *tmps;
- unsigned long value;
I32 argtype;
tmps = POPp;
- value = scan_hex(tmps, 99, &argtype);
- if ((IV)value >= 0)
- XPUSHi(value);
- else
- XPUSHn(U_V(value));
+ XPUSHu(scan_hex(tmps, 99, &argtype));
RETURN;
}
PP(pp_oct)
{
dSP; dTARGET;
- unsigned long value;
+ UV value;
I32 argtype;
char *tmps;
@@ -1399,10 +1390,7 @@ PP(pp_oct)
value = scan_hex(++tmps, 99, &argtype);
else
value = scan_oct(tmps, 99, &argtype);
- if ((IV)value >= 0)
- XPUSHi(value);
- else
- XPUSHn(U_V(value));
+ XPUSHu(value);
RETURN;
}
@@ -2330,6 +2318,35 @@ PP(pp_reverse)
RETURN;
}
+static SV *
+mul128(sv, m)
+ SV *sv;
+ U8 m;
+{
+ STRLEN len;
+ char *s = SvPV(sv, len);
+ char *t;
+ U32 i = 0;
+
+ if (!strnEQ(s, "0000", 4)) { /* need to grow sv */
+ SV *new = newSVpv("0000000000", 10);
+
+ sv_catsv(new, sv);
+ SvREFCNT_dec(sv); /* free old sv */
+ sv = new;
+ s = SvPV(sv, len);
+ }
+ t = s + len - 1;
+ while (!*t) /* trailing '\0'? */
+ t--;
+ while (t > s) {
+ i = ((*t - '0') << 7) + m;
+ *(t--) = '0' + (i % 10);
+ m = i / 10;
+ }
+ return (sv);
+}
+
/* Explosives and implosives. */
PP(pp_unpack)
@@ -2800,7 +2817,7 @@ PP(pp_unpack)
while (len > 0) {
if (s >= strend) {
if (auint) {
- DIE("Unterminated compressed integer");
+ croak("Unterminated compressed integer");
} else {
break;
}
@@ -2813,17 +2830,29 @@ PP(pp_unpack)
len--;
auint = 0;
bytes = 0;
- } else if (++bytes >= sizeof(auint)) { /* promote to double */
- adouble = auint;
+ } else if (++bytes >= sizeof(auint)) { /* promote to string */
+ char zero[10];
+ (void) sprintf(zero, "%010ld", auint);
+ sv = newSVpv(zero, 10);
+
while (*s & 0x80) {
- adouble = (adouble * 128) + (*(++s) & 0x7f);
+ sv = mul128(sv, (U8) (*(++s) & 0x7f));
if (s >= strend) {
- DIE("Unterminated compressed integer");
+ croak("Unterminated compressed integer");
}
}
- sv = NEWSV(40, 0);
- sv_setnv(sv, adouble);
+ /* remove leading '0's */
+ {
+ char *s = SvPV(sv, na);
+
+ while (*s == '0') {
+ s++;
+ na--;
+ }
+ /* overlapping copy !! */
+ sv_setpvn(sv, s, na);
+ }
PUSHs(sv_2mortal(sv));
len--;
auint = 0;
@@ -3029,6 +3058,85 @@ register I32 len;
sv_catpvn(sv, "\n", 1);
}
+static SV *
+is_an_int(s, l)
+ char *s;
+ STRLEN l;
+{
+ SV *result = newSVpv("", l);
+ char *result_c = SvPV(result, na); /* convenience */
+ char *out = result_c;
+ bool skip = 1;
+ bool ignore = 0;
+
+ while (*s) {
+ switch (*s) {
+ case ' ':
+ break;
+ case '+':
+ if (!skip) {
+ SvREFCNT_dec(result);
+ return (NULL);
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ skip = 0;
+ if (!ignore) {
+ *(out++) = *s;
+ }
+ break;
+ case '.':
+ ignore = 1;
+ break;
+ default:
+ SvREFCNT_dec(result);
+ return (NULL);
+ }
+ s++;
+ }
+ *(out++) = '\0';
+ SvCUR_set(result, out - result_c);
+ return (result);
+}
+
+static int
+div128(pnum, done)
+ SV *pnum; /* must be '\0' terminated */
+ bool *done;
+{
+ STRLEN len;
+ char *s = SvPV(pnum, len);
+ int m = 0;
+ int r = 0;
+ char *t = s;
+
+ *done = 1;
+ while (*t) {
+ int i;
+
+ i = m * 10 + (*t - '0');
+ m = i & 0x7F;
+ r = (i >> 7); /* r < 10 */
+ if (r) {
+ *done = 0;
+ }
+ *(t++) = '0' + r;
+ }
+ *(t++) = '\0';
+ SvCUR_set(pnum, (STRLEN) (t - s));
+ return (m);
+}
+
+
PP(pp_pack)
{
dSP; dMARK; dORIGMARK; dTARGET;
@@ -3313,34 +3421,64 @@ PP(pp_pack)
fromstr = NEXTFROM;
adouble = floor((double)SvNV(fromstr));
- if (adouble < 268435456) { /* we can use integers */
- unsigned char buf[4]; /* buffer for compressed int */
- unsigned char *in = buf + 3;
+ if (adouble <= PERL_ULONG_MAX) { /* we can use integers */
+ unsigned char buf[5]; /* buffer for compressed int */
+ unsigned char *in = buf + 4;
+
auint = U_I(adouble);
+
do {
*(in--) = (unsigned char) ((auint & 0x7f) | 0x80);
auint >>= 7;
} while (auint);
- buf[3] &= 0x7f; /* clear continue bit */
- sv_catpvn(cat, (char*) in+1, buf+3-in);
+ buf[4] &= 0x7f; /* clear continue bit */
+ sv_catpvn(cat, (char *) in + 1, buf + 4 - in);
+ } else if (SvPOKp(fromstr)) { /* decimal string arithmetics */
+ char *from;
+ SV *norm;
+ STRLEN len;
+
+ /* Copy string and check for compliance */
+ from = SvPV(fromstr, len);
+ if ((norm = is_an_int(from, len)) == NULL) {
+ croak("can compress only unsigned integer");
} else {
- unsigned char buf[sizeof(double)*2]; /* buffer for compressed int */
- I8 msize = sizeof(double)*2; /* 8/7 would be enough */
+ bool done = 0;
+ char *result, *in;
+
+ New('w', result, len, char);
+ in = result + len;
+ while (!done) {
+ U8 digit = div128(norm, &done);
+
+ *(--in) = digit | 0x80;
+ }
+ result[len - 1] &= 0x7F;
+ sv_catpvn(cat, in, result + len - in);
+ SvREFCNT_dec(norm); /* free norm */
+ }
+ } else if (SvNOKp(fromstr)) {
+ I8 msize = sizeof(double) * 2; /* 8/7 <= 2 */
+ unsigned char buf[sizeof(double) * 2];
unsigned char *in = buf + msize -1;
+
if (adouble<0) {
croak("Cannot compress negative numbers");
}
do {
double next = adouble/128;
+
*in = (unsigned char) (adouble - floor(next)*128);
*in |= 0x80; /* set continue bit */
if (--in < buf) { /* this cannot happen ;-) */
croak ("Cannot compress integer");
}
adouble = next;
- } while (floor(adouble)>0); /* floor() not necessary? */
+ } while (floor(adouble)); /* floor() not necessary? */
buf[msize-1] &= 0x7f; /* clear continue bit */
sv_catpvn(cat, (char*) in+1, buf+msize-in-1);
+ } else {
+ croak("Cannot compress non integer");
}
}
break;