/* pp_pack.c
*
* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- * 2000, 2001, 2002, 2003, 2004, 2005, by Larry Wall and others
+ * 2000, 2001, 2002, 2003, 2004, 2005, 2006, 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.
(symptr)->grpend = NULL; \
(symptr)->code = 0; \
(symptr)->length = 0; \
- (symptr)->howlen = 0; \
+ (symptr)->howlen = e_no_len; \
(symptr)->level = 0; \
(symptr)->flags = (f); \
(symptr)->strbeg = 0; \
char *t;
if (!strnEQ(s, "0000", 4)) { /* need to grow sv */
- SV * const tmpNew = newSVpvn("0000000000", 10);
+ SV * const tmpNew = newSVpvs("0000000000");
sv_catsv(tmpNew, sv);
SvREFCNT_dec(sv); /* free old sv */
# define DO_BO_PACK_P(var) DO_BO_PACK_PTR(var, l, long, void)
# define DO_BO_UNPACK_PC(var) DO_BO_UNPACK_PTR(var, l, long, char)
# define DO_BO_PACK_PC(var) DO_BO_PACK_PTR(var, l, long, char)
+# elif PTRSIZE == IVSIZE
+# define DO_BO_UNPACK_P(var) DO_BO_UNPACK_PTR(var, l, IV, void)
+# define DO_BO_PACK_P(var) DO_BO_PACK_PTR(var, l, IV, void)
+# define DO_BO_UNPACK_PC(var) DO_BO_UNPACK_PTR(var, l, IV, char)
+# define DO_BO_PACK_PC(var) DO_BO_PACK_PTR(var, l, IV, char)
# else
# define DO_BO_UNPACK_P(var) BO_CANT_DOIT(unpack, pointer)
# define DO_BO_PACK_P(var) BO_CANT_DOIT(pack, pointer)
STATIC bool
next_uni_uu(pTHX_ const char **s, const char *end, I32 *out)
{
+ dVAR;
STRLEN retlen;
const UV val = utf8n_to_uvchr((U8 *) *s, end-*s, &retlen, UTF8_CHECK_ONLY);
if (val >= 0x100 || !ISUUCHAR(val) ||
return TRUE;
}
-STATIC void
-bytes_to_uni(pTHX_ const U8 *start, STRLEN len, char **dest) {
- U8 buffer[UTF8_MAXLEN];
+STATIC char *
+S_bytes_to_uni(const U8 *start, STRLEN len, char *dest) {
const U8 * const end = start + len;
- char *d = *dest;
+
while (start < end) {
- const int length =
- uvuni_to_utf8_flags(buffer, NATIVE_TO_UNI(*start), 0) - buffer;
- switch(length) {
- case 1:
- *d++ = buffer[0];
- break;
- case 2:
- *d++ = buffer[0];
- *d++ = buffer[1];
- break;
- default:
- Perl_croak(aTHX_ "Perl bug: value %d UTF-8 expands to %d bytes",
- *start, length);
+ const UV uv = NATIVE_TO_ASCII(*start);
+ if (UNI_IS_INVARIANT(uv))
+ *dest++ = (char)(U8)UTF_TO_NATIVE(uv);
+ else {
+ *dest++ = (char)(U8)UTF8_EIGHT_BIT_HI(uv);
+ *dest++ = (char)(U8)UTF8_EIGHT_BIT_LO(uv);
}
start++;
}
- *dest = d;
+ return dest;
}
#define PUSH_BYTES(utf8, cur, buf, len) \
STMT_START { \
- if (utf8) bytes_to_uni(aTHX_ (U8 *) buf, len, &(cur)); \
+ if (utf8) \
+ (cur) = bytes_to_uni((U8 *) buf, len, (cur)); \
else { \
Copy(buf, cur, len, char); \
(cur) += (len); \
STRLEN glen = (in_len); \
if (utf8) glen *= UTF8_EXPAND; \
if ((cur) + glen >= (start) + SvLEN(cat)) { \
- (start) = sv_exp_grow(aTHX_ cat, glen); \
+ (start) = sv_exp_grow(cat, glen); \
(cur) = (start) + SvCUR(cat); \
} \
} STMT_END
if ((cur) + gl >= (start) + SvLEN(cat)) { \
*cur = '\0'; \
SvCUR_set((cat), (cur) - (start)); \
- (start) = sv_exp_grow(aTHX_ cat, gl); \
+ (start) = sv_exp_grow(cat, gl); \
(cur) = (start) + SvCUR(cat); \
} \
PUSH_BYTES(utf8, cur, buf, glen); \
STMT_START { \
if (utf8) { \
const U8 au8 = (byte); \
- bytes_to_uni(aTHX_ &au8, 1, &(s)); \
+ (s) = bytes_to_uni(&au8, 1, (s)); \
} else *(U8 *)(s)++ = (byte); \
} STMT_END
static const char *_action( const tempsym_t* symptr )
{
- return ( symptr->flags & FLAG_PACK ) ? "pack" : "unpack";
+ return (const char *)(( symptr->flags & FLAG_PACK ) ? "pack" : "unpack");
}
/* Returns the sizeof() struct described by pat */
}
/*
-=for apidoc unpack_str
-
-The engine implementing unpack() Perl function. Note: parameters strbeg, new_s
-and ocnt are not used. This call should not be used, use unpackstring instead.
-
-=cut */
-
-I32
-Perl_unpack_str(pTHX_ const char *pat, const char *patend, const char *s, const char *strbeg, const char *strend, char **new_s, I32 ocnt, U32 flags)
-{
- tempsym_t sym;
- PERL_UNUSED_ARG(strbeg);
- PERL_UNUSED_ARG(new_s);
- PERL_UNUSED_ARG(ocnt);
-
- if (flags & FLAG_DO_UTF8) flags |= FLAG_WAS_UTF8;
- else if (need_utf8(pat, patend)) {
- /* We probably should try to avoid this in case a scalar context call
- wouldn't get to the "U0" */
- STRLEN len = strend - s;
- s = (char *) bytes_to_utf8((U8 *) s, &len);
- SAVEFREEPV(s);
- strend = s + len;
- flags |= FLAG_DO_UTF8;
- }
-
- if (first_symbol(pat, patend) != 'U' && (flags & FLAG_DO_UTF8))
- flags |= FLAG_PARSE_UTF8;
-
- TEMPSYM_INIT(&sym, pat, patend, flags);
-
- return unpack_rec(&sym, s, s, strend, NULL );
-}
-
-/*
=for apidoc unpackstring
The engine implementing unpack() Perl function. C<unpackstring> puts the
break;
}
- sv = sv_2mortal(NEWSV(35, len ? len : 1));
+ sv = sv_2mortal(newSV(len ? len : 1));
SvPOK_on(sv);
str = SvPVX(sv);
if (datumtype == 'b') {
/* Preliminary length estimate, acceptable for utf8 too */
if (howlen == e_star || len > (strend - s) * 2)
len = (strend - s) * 2;
- sv = sv_2mortal(NEWSV(35, len ? len : 1));
+ sv = sv_2mortal(newSV(len ? len : 1));
SvPOK_on(sv);
str = SvPVX(sv);
if (datumtype == 'h') {
if (symptr->howlen == e_star)
Perl_croak(aTHX_ "'P' must have an explicit size in unpack");
EXTEND(SP, 1);
- if (sizeof(char*) <= strend - s) {
+ if (s + sizeof(char*) <= strend) {
char *aptr;
SHIFT_VAR(utf8, s, strend, aptr, datumtype);
DO_BO_UNPACK_PC(aptr);
* algorithm, the code will be character-set independent
* (and just as fast as doing character arithmetic)
*/
- if (PL_uudmap['M'] == 0) {
- int i;
+ if (PL_uudmap[(U8)'M'] == 0) {
+ size_t i;
- for (i = 0; i < sizeof(PL_uuemap); i += 1)
+ for (i = 0; i < sizeof(PL_uuemap); ++i)
PL_uudmap[(U8)PL_uuemap[i]] = i;
/*
* Because ' ' and '`' map to the same value,
* we need to decode them both the same.
*/
- PL_uudmap[' '] = 0;
+ PL_uudmap[(U8)' '] = 0;
}
{
const STRLEN l = (STRLEN) (strend - s) * 3 / 4;
- sv = sv_2mortal(NEWSV(42, l));
+ sv = sv_2mortal(newSV(l));
if (l) SvPOK_on(sv);
}
if (utf8) {
PP(pp_unpack)
{
+ dVAR;
dSP;
dPOPPOPssrl;
I32 gimme = GIMME_V;
}
/*
-=for apidoc pack_cat
-
-The engine implementing pack() Perl function. Note: parameters next_in_list and
-flags are not used. This call should not be used; use packlist instead.
-
-=cut
-*/
-
-void
-Perl_pack_cat(pTHX_ SV *cat, const char *pat, const char *patend, register SV **beglist, SV **endlist, SV ***next_in_list, U32 flags)
-{
- tempsym_t sym;
- PERL_UNUSED_ARG(next_in_list);
- PERL_UNUSED_ARG(flags);
-
- TEMPSYM_INIT(&sym, pat, patend, FLAG_PACK);
-
- (void)pack_rec( cat, &sym, beglist, endlist );
-}
-
-
-/*
=for apidoc packlist
The engine implementing pack() Perl function.
void
Perl_packlist(pTHX_ SV *cat, const char *pat, const char *patend, register SV **beglist, SV **endlist )
{
- STRLEN no_len;
+ dVAR;
tempsym_t sym;
TEMPSYM_INIT(&sym, pat, patend, FLAG_PACK);
/* We're going to do changes through SvPVX(cat). Make sure it's valid.
Also make sure any UTF8 flag is loaded */
- SvPV_force(cat, no_len);
+ SvPV_force_nolen(cat);
if (DO_UTF8(cat))
sym.flags |= FLAG_PARSE_UTF8 | FLAG_DO_UTF8;
Only grows the string if there is an actual lack of space
*/
STATIC char *
-sv_exp_grow(pTHX_ SV *sv, STRLEN needed) {
+S_sv_exp_grow(pTHX_ SV *sv, STRLEN needed) {
const STRLEN cur = SvCUR(sv);
const STRLEN len = SvLEN(sv);
STRLEN extend;
SV **
S_pack_rec(pTHX_ SV *cat, tempsym_t* symptr, SV **beglist, SV **endlist )
{
+ dVAR;
tempsym_t lookahead;
I32 items = endlist - beglist;
bool found = next_symbol(symptr);
SV *fromstr;
STRLEN fromlen;
I32 len;
- SV *lengthcode = Nullsv;
+ SV *lengthcode = NULL;
I32 datumtype = symptr->code;
howlen_t howlen = symptr->howlen;
char *start = SvPVX(cat);
if (strchr("aAZ", lookahead.code)) {
if (lookahead.howlen == e_number) count = lookahead.length;
else {
- if (items > 0)
+ if (items > 0) {
+ if (SvGAMAGIC(*beglist)) {
+ /* Avoid reading the active data more than once
+ by copying it to a temporary. */
+ STRLEN len;
+ const char *const pv = SvPV_const(*beglist, len);
+ SV *const temp = sv_2mortal(newSVpvn(pv, len));
+ if (SvUTF8(*beglist))
+ SvUTF8_on(temp);
+ *beglist = temp;
+ }
count = DO_UTF8(*beglist) ?
sv_len_utf8(*beglist) : sv_len(*beglist);
+ }
else count = 0;
if (lookahead.code == 'Z') count++;
}
if (datumtype == 'B')
while (l++ < len) {
if (utf8_source) {
- UV val;
+ UV val = 0;
NEXT_UNI_VAL(val, cur, str, end, utf8_flags);
bits |= val & 1;
} else bits |= *str++ & 1;
/* datumtype == 'b' */
while (l++ < len) {
if (utf8_source) {
- UV val;
+ UV val = 0;
NEXT_UNI_VAL(val, cur, str, end, utf8_flags);
if (val & 1) bits |= 0x80;
} else if (*str++ & 1)
if (datumtype == 'H')
while (l++ < len) {
if (utf8_source) {
- UV val;
+ UV val = 0;
NEXT_UNI_VAL(val, cur, str, end, utf8_flags);
if (val < 256 && isALPHA(val))
bits |= (val + 9) & 0xf;
else
while (l++ < len) {
if (utf8_source) {
- UV val;
+ UV val = 0;
NEXT_UNI_VAL(val, cur, str, end, utf8_flags);
if (val < 256 && isALPHA(val))
bits |= ((val + 9) & 0xf) << 4;
break;
case 'W': {
char *end;
- U8 in_bytes = IN_BYTES;
+ U8 in_bytes = (U8)IN_BYTES;
end = start+SvLEN(cat)-1;
if (utf8) end -= UTF8_MAXLEN-1;
len+(endb-buffer)*UTF8_EXPAND);
end = start+SvLEN(cat);
}
- bytes_to_uni(aTHX_ buffer, endb-buffer, &cur);
+ cur = bytes_to_uni(buffer, endb-buffer, cur);
} else {
if (cur >= end) {
*cur = '\0';
PP(pp_pack)
{
- dSP; dMARK; dORIGMARK; dTARGET;
+ dVAR; dSP; dMARK; dORIGMARK; dTARGET;
register SV *cat = TARG;
STRLEN fromlen;
SV *pat_sv = *++MARK;