This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
tr///c: handle len(replacement charlist) > 32767
[perl5.git] / doop.c
1 /*    doop.c
2  *
3  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
4  *    2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 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  *  'So that was the job I felt I had to do when I started,' thought Sam.
13  *
14  *     [p.934 of _The Lord of the Rings_, VI/iii: "Mount Doom"]
15  */
16
17 /* This file contains some common functions needed to carry out certain
18  * ops. For example, both pp_sprintf() and pp_prtf() call the function
19  * do_sprintf() found in this file.
20  */
21
22 #include "EXTERN.h"
23 #define PERL_IN_DOOP_C
24 #include "perl.h"
25
26 #ifndef PERL_MICRO
27 #include <signal.h>
28 #endif
29
30
31 /* Helper function for do_trans().
32  * Handles non-utf8 cases(*) not involving the /c, /d, /s flags,
33  * and where search and replacement charlists aren't identical.
34  * (*) i.e. where the search and replacement charlists are non-utf8. sv may
35  * or may not be utf8.
36  */
37
38 STATIC I32
39 S_do_trans_simple(pTHX_ SV * const sv)
40 {
41     I32 matches = 0;
42     STRLEN len;
43     U8 *s = (U8*)SvPV_nomg(sv,len);
44     U8 * const send = s+len;
45     const OPtrans_map * const tbl = (OPtrans_map*)cPVOP->op_pv;
46
47     PERL_ARGS_ASSERT_DO_TRANS_SIMPLE;
48
49     if (!tbl)
50         Perl_croak(aTHX_ "panic: do_trans_simple line %d",__LINE__);
51
52     /* First, take care of non-UTF-8 input strings, because they're easy */
53     if (!SvUTF8(sv)) {
54         while (s < send) {
55             const I32 ch = tbl->map[*s];
56             if (ch >= 0) {
57                 matches++;
58                 *s = (U8)ch;
59             }
60             s++;
61         }
62         SvSETMAGIC(sv);
63     }
64     else {
65         const I32 grows = PL_op->op_private & OPpTRANS_GROWS;
66         U8 *d;
67         U8 *dstart;
68
69         /* Allow for expansion: $_="a".chr(400); tr/a/\xFE/, FE needs encoding */
70         if (grows)
71             Newx(d, len*2+1, U8);
72         else
73             d = s;
74         dstart = d;
75         while (s < send) {
76             STRLEN ulen;
77             I32 ch;
78
79             /* Need to check this, otherwise 128..255 won't match */
80             const UV c = utf8n_to_uvchr(s, send - s, &ulen, UTF8_ALLOW_DEFAULT);
81             if (c < 0x100 && (ch = tbl->map[c]) >= 0) {
82                 matches++;
83                 d = uvchr_to_utf8(d, ch);
84                 s += ulen;
85             }
86             else { /* No match -> copy */
87                 Move(s, d, ulen, U8);
88                 d += ulen;
89                 s += ulen;
90             }
91         }
92         if (grows) {
93             sv_setpvn(sv, (char*)dstart, d - dstart);
94             Safefree(dstart);
95         }
96         else {
97             *d = '\0';
98             SvCUR_set(sv, d - dstart);
99         }
100         SvUTF8_on(sv);
101         SvSETMAGIC(sv);
102     }
103     return matches;
104 }
105
106
107 /* Helper function for do_trans().
108  * Handles non-utf8 cases(*) where search and replacement charlists are
109  * identical: so the string isn't modified, and only a count of modifiable
110  * chars is needed.
111  * Note that it doesn't handle /d or /s, since these modify the string
112  * even if the replacement list is empty.
113  * (*) i.e. where the search and replacement charlists are non-utf8. sv may
114  * or may not be utf8.
115  */
116
117 STATIC I32
118 S_do_trans_count(pTHX_ SV * const sv)
119 {
120     STRLEN len;
121     const U8 *s = (const U8*)SvPV_nomg_const(sv, len);
122     const U8 * const send = s + len;
123     I32 matches = 0;
124     const OPtrans_map * const tbl = (OPtrans_map*)cPVOP->op_pv;
125
126     PERL_ARGS_ASSERT_DO_TRANS_COUNT;
127
128     if (!tbl)
129         Perl_croak(aTHX_ "panic: do_trans_count line %d",__LINE__);
130
131     if (!SvUTF8(sv)) {
132         while (s < send) {
133             if (tbl->map[*s++] >= 0)
134                 matches++;
135         }
136     }
137     else {
138         const I32 complement = PL_op->op_private & OPpTRANS_COMPLEMENT;
139         while (s < send) {
140             STRLEN ulen;
141             const UV c = utf8n_to_uvchr(s, send - s, &ulen, UTF8_ALLOW_DEFAULT);
142             if (c < 0x100) {
143                 if (tbl->map[c] >= 0)
144                     matches++;
145             } else if (complement)
146                 matches++;
147             s += ulen;
148         }
149     }
150
151     return matches;
152 }
153
154
155 /* Helper function for do_trans().
156  * Handles non-utf8 cases(*) involving the /c, /d, /s flags,
157  * and where search and replacement charlists aren't identical.
158  * (*) i.e. where the search and replacement charlists are non-utf8. sv may
159  * or may not be utf8.
160  */
161
162 STATIC I32
163 S_do_trans_complex(pTHX_ SV * const sv)
164 {
165     STRLEN len;
166     U8 *s = (U8*)SvPV_nomg(sv, len);
167     U8 * const send = s+len;
168     I32 matches = 0;
169     const OPtrans_map_ex * const extbl = (OPtrans_map_ex*)cPVOP->op_pv;
170
171     PERL_ARGS_ASSERT_DO_TRANS_COMPLEX;
172
173     if (!extbl)
174         Perl_croak(aTHX_ "panic: do_trans_complex line %d",__LINE__);
175
176     if (!SvUTF8(sv)) {
177         U8 *d = s;
178         U8 * const dstart = d;
179
180         if (PL_op->op_private & OPpTRANS_SQUASH) {
181             const U8* p = send;
182             while (s < send) {
183                 const I32 ch = extbl->map[*s];
184                 if (ch >= 0) {
185                     *d = (U8)ch;
186                     matches++;
187                     if (p != d - 1 || *p != *d)
188                         p = d++;
189                 }
190                 else if (ch == -1)      /* -1 is unmapped character */
191                     *d++ = *s;  
192                 else if (ch == -2)      /* -2 is delete character */
193                     matches++;
194                 s++;
195             }
196         }
197         else {
198             while (s < send) {
199                 const I32 ch = extbl->map[*s];
200                 if (ch >= 0) {
201                     matches++;
202                     *d++ = (U8)ch;
203                 }
204                 else if (ch == -1)      /* -1 is unmapped character */
205                     *d++ = *s;
206                 else if (ch == -2)      /* -2 is delete character */
207                     matches++;
208                 s++;
209             }
210         }
211         *d = '\0';
212         SvCUR_set(sv, d - dstart);
213     }
214     else { /* is utf8 */
215         const I32 complement = PL_op->op_private & OPpTRANS_COMPLEMENT;
216         const I32 grows = PL_op->op_private & OPpTRANS_GROWS;
217         const I32 del = PL_op->op_private & OPpTRANS_DELETE;
218         U8 *d;
219         U8 *dstart;
220         SSize_t excess = 0;
221
222         if (grows)
223             Newx(d, len*2+1, U8);
224         else
225             d = s;
226         dstart = d;
227         if (complement)
228             /* number of replacement chars in excess of any 0x00..0xff
229              * search characters */
230             excess = extbl->excess_len;
231
232         if (PL_op->op_private & OPpTRANS_SQUASH) {
233             UV pch = 0xfeedface;
234             while (s < send) {
235                 STRLEN len;
236                 const UV comp = utf8n_to_uvchr(s, send - s, &len,
237                                                UTF8_ALLOW_DEFAULT);
238                 UV     ch;
239                 short sch;
240
241                 if (comp > 0xff) {
242                     if (!complement) {
243                         Move(s, d, len, U8);
244                         d += len;
245                     }
246                     else {
247                         /* use the implicit 0x100..0x7fffffff search range */
248                         UV comp100 = comp - 0x100;
249                         matches++;
250                         ch = del
251                                /* setting ch to pch forces char to be deleted */
252                              ? ((excess > (IV)comp100)
253                                             ? (UV)extbl->map_ex[comp100]
254                                             : pch           )
255
256                              : (        (excess == -1) ? comp :
257                                  (UV)((  excess ==  0
258                                       || excess <= (IV)comp100)
259                                             ? extbl->repeat_char
260                                             : extbl->map_ex[comp100]
261                                      )
262                                );
263                         if (ch != pch) {
264                             d = uvchr_to_utf8(d, ch);
265                             pch = ch;
266                         }
267                         s += len;
268                         continue;
269                     }
270                 }
271                 else if ((sch = extbl->map[comp]) >= 0) {
272                     ch = (UV)sch;
273                     matches++;
274                     if (ch != pch) {
275                         d = uvchr_to_utf8(d, ch);
276                         pch = ch;
277                     }
278                     s += len;
279                     continue;
280                 }
281                 else if (sch == -1) {   /* -1 is unmapped character */
282                     Move(s, d, len, U8);
283                     d += len;
284                 }
285                 else if (sch == -2)      /* -2 is delete character */
286                     matches++;
287                 s += len;
288                 pch = 0xfeedface;
289             }
290         }
291         else {
292             while (s < send) {
293                 STRLEN len;
294                 const UV comp = utf8n_to_uvchr(s, send - s, &len,
295                                                UTF8_ALLOW_DEFAULT);
296                 UV     ch;
297                 short sch;
298                 if (comp > 0xff) {
299                     if (!complement) {
300                         Move(s, d, len, U8);
301                         d += len;
302                     }
303                     else {
304                         /* use the implicit 0x100..0x7fffffff search range */
305                         UV comp100 = comp - 0x100;
306                         matches++;
307                         if (del) {
308                              if (excess > (IV)comp100) {
309                                 ch = (UV)extbl->map_ex[comp100];
310                                 d = uvchr_to_utf8(d, ch);
311                             }
312                         }
313                         else {
314                             /* tr/...//c should call S_do_trans_count
315                              * instead */
316                             assert(excess != -1);
317                             ch = (   excess ==  0
318                                       || excess <= (IV)comp100)
319                                             ? (UV)extbl->repeat_char
320                                             : (UV)extbl->map_ex[comp100];
321                             d = uvchr_to_utf8(d, ch);
322                         }
323                     }
324                 }
325                 else if ((sch = extbl->map[comp]) >= 0) {
326                     d = uvchr_to_utf8(d, (UV)sch);
327                     matches++;
328                 }
329                 else if (sch == -1) {   /* -1 is unmapped character */
330                     Move(s, d, len, U8);
331                     d += len;
332                 }
333                 else if (sch == -2)      /* -2 is delete character */
334                     matches++;
335                 s += len;
336             }
337         }
338         if (grows) {
339             sv_setpvn(sv, (char*)dstart, d - dstart);
340             Safefree(dstart);
341         }
342         else {
343             *d = '\0';
344             SvCUR_set(sv, d - dstart);
345         }
346         SvUTF8_on(sv);
347     }
348     SvSETMAGIC(sv);
349     return matches;
350 }
351
352
353 /* Helper function for do_trans().
354  * Handles utf8 cases(*) not involving the /c, /d, /s flags,
355  * and where search and replacement charlists aren't identical.
356  * (*) i.e. where the search or replacement charlists are utf8. sv may
357  * or may not be utf8.
358  */
359
360 STATIC I32
361 S_do_trans_simple_utf8(pTHX_ SV * const sv)
362 {
363     U8 *s;
364     U8 *send;
365     U8 *d;
366     U8 *start;
367     U8 *dstart, *dend;
368     I32 matches = 0;
369     const I32 grows = PL_op->op_private & OPpTRANS_GROWS;
370     STRLEN len;
371     SV* const  rv =
372 #ifdef USE_ITHREADS
373                     PAD_SVl(cPADOP->op_padix);
374 #else
375                     MUTABLE_SV(cSVOP->op_sv);
376 #endif
377     HV* const  hv = MUTABLE_HV(SvRV(rv));
378     SV* const * svp = hv_fetchs(hv, "NONE", FALSE);
379     const UV none = svp ? SvUV(*svp) : 0x7fffffff;
380     const UV extra = none + 1;
381     UV final = 0;
382     U8 hibit = 0;
383
384     PERL_ARGS_ASSERT_DO_TRANS_SIMPLE_UTF8;
385
386     s = (U8*)SvPV_nomg(sv, len);
387     if (!SvUTF8(sv)) {
388         hibit = ! is_utf8_invariant_string(s, len);
389         if (hibit) {
390             s = bytes_to_utf8(s, &len);
391         }
392     }
393     send = s + len;
394     start = s;
395
396     svp = hv_fetchs(hv, "FINAL", FALSE);
397     if (svp)
398         final = SvUV(*svp);
399
400     if (grows) {
401         /* d needs to be bigger than s, in case e.g. upgrading is required */
402         Newx(d, len * 3 + UTF8_MAXBYTES, U8);
403         dend = d + len * 3;
404         dstart = d;
405     }
406     else {
407         dstart = d = s;
408         dend = d + len;
409     }
410
411     while (s < send) {
412         const UV uv = swash_fetch(rv, s, TRUE);
413         if (uv < none) {
414             s += UTF8SKIP(s);
415             matches++;
416             d = uvchr_to_utf8(d, uv);
417         }
418         else if (uv == none) {
419             const int i = UTF8SKIP(s);
420             Move(s, d, i, U8);
421             d += i;
422             s += i;
423         }
424         else if (uv == extra) {
425             s += UTF8SKIP(s);
426             matches++;
427             d = uvchr_to_utf8(d, final);
428         }
429         else
430             s += UTF8SKIP(s);
431
432         if (d > dend) {
433             const STRLEN clen = d - dstart;
434             const STRLEN nlen = dend - dstart + len + UTF8_MAXBYTES;
435             if (!grows)
436                 Perl_croak(aTHX_ "panic: do_trans_simple_utf8 line %d",__LINE__);
437             Renew(dstart, nlen + UTF8_MAXBYTES, U8);
438             d = dstart + clen;
439             dend = dstart + nlen;
440         }
441     }
442     if (grows || hibit) {
443         sv_setpvn(sv, (char*)dstart, d - dstart);
444         Safefree(dstart);
445         if (grows && hibit)
446             Safefree(start);
447     }
448     else {
449         *d = '\0';
450         SvCUR_set(sv, d - dstart);
451     }
452     SvSETMAGIC(sv);
453     SvUTF8_on(sv);
454
455     return matches;
456 }
457
458
459 /* Helper function for do_trans().
460  * Handles utf8 cases(*) where search and replacement charlists are
461  * identical: so the string isn't modified, and only a count of modifiable
462  * chars is needed.
463  * Note that it doesn't handle /d or /s, since these modify the string
464  * even if the replacement charlist is empty.
465  * (*) i.e. where the search or replacement charlists are utf8. sv may
466  * or may not be utf8.
467  */
468
469 STATIC I32
470 S_do_trans_count_utf8(pTHX_ SV * const sv)
471 {
472     const U8 *s;
473     const U8 *start = NULL;
474     const U8 *send;
475     I32 matches = 0;
476     STRLEN len;
477     SV* const  rv =
478 #ifdef USE_ITHREADS
479                     PAD_SVl(cPADOP->op_padix);
480 #else
481                     MUTABLE_SV(cSVOP->op_sv);
482 #endif
483     HV* const hv = MUTABLE_HV(SvRV(rv));
484     SV* const * const svp = hv_fetchs(hv, "NONE", FALSE);
485     const UV none = svp ? SvUV(*svp) : 0x7fffffff;
486     const UV extra = none + 1;
487     U8 hibit = 0;
488
489     PERL_ARGS_ASSERT_DO_TRANS_COUNT_UTF8;
490
491     s = (const U8*)SvPV_nomg_const(sv, len);
492     if (!SvUTF8(sv)) {
493         hibit = ! is_utf8_invariant_string(s, len);
494         if (hibit) {
495             start = s = bytes_to_utf8(s, &len);
496         }
497     }
498     send = s + len;
499
500     while (s < send) {
501         const UV uv = swash_fetch(rv, s, TRUE);
502         if (uv < none || uv == extra)
503             matches++;
504         s += UTF8SKIP(s);
505     }
506     if (hibit)
507         Safefree(start);
508
509     return matches;
510 }
511
512
513 /* Helper function for do_trans().
514  * Handles utf8 cases(*) involving the /c, /d, /s flags,
515  * and where search and replacement charlists aren't identical.
516  * (*) i.e. where the search or replacement charlists are utf8. sv may
517  * or may not be utf8.
518  */
519
520 STATIC I32
521 S_do_trans_complex_utf8(pTHX_ SV * const sv)
522 {
523     U8 *start, *send;
524     U8 *d;
525     I32 matches = 0;
526     const I32 squash   = PL_op->op_private & OPpTRANS_SQUASH;
527     const I32 del      = PL_op->op_private & OPpTRANS_DELETE;
528     const I32 grows    = PL_op->op_private & OPpTRANS_GROWS;
529     SV* const  rv =
530 #ifdef USE_ITHREADS
531                     PAD_SVl(cPADOP->op_padix);
532 #else
533                     MUTABLE_SV(cSVOP->op_sv);
534 #endif
535     HV * const hv = MUTABLE_HV(SvRV(rv));
536     SV * const *svp = hv_fetchs(hv, "NONE", FALSE);
537     const UV none = svp ? SvUV(*svp) : 0x7fffffff;
538     const UV extra = none + 1;
539     UV final = 0;
540     bool havefinal = FALSE;
541     STRLEN len;
542     U8 *dstart, *dend;
543     U8 hibit = 0;
544     U8 *s = (U8*)SvPV_nomg(sv, len);
545
546     PERL_ARGS_ASSERT_DO_TRANS_COMPLEX_UTF8;
547
548     if (!SvUTF8(sv)) {
549         hibit = ! is_utf8_invariant_string(s, len);
550         if (hibit) {
551             s = bytes_to_utf8(s, &len);
552         }
553     }
554     send = s + len;
555     start = s;
556
557     svp = hv_fetchs(hv, "FINAL", FALSE);
558     if (svp) {
559         final = SvUV(*svp);
560         havefinal = TRUE;
561     }
562
563     if (grows) {
564         /* d needs to be bigger than s, in case e.g. upgrading is required */
565         Newx(d, len * 3 + UTF8_MAXBYTES, U8);
566         dend = d + len * 3;
567         dstart = d;
568     }
569     else {
570         dstart = d = s;
571         dend = d + len;
572     }
573
574     if (squash) {
575         UV puv = 0xfeedface;
576         while (s < send) {
577             UV uv = swash_fetch(rv, s, TRUE);
578         
579             if (d > dend) {
580                 const STRLEN clen = d - dstart;
581                 const STRLEN nlen = dend - dstart + len + UTF8_MAXBYTES;
582                 if (!grows)
583                     Perl_croak(aTHX_ "panic: do_trans_complex_utf8 line %d",__LINE__);
584                 Renew(dstart, nlen + UTF8_MAXBYTES, U8);
585                 d = dstart + clen;
586                 dend = dstart + nlen;
587             }
588             if (uv < none) {
589                 matches++;
590                 s += UTF8SKIP(s);
591                 if (uv != puv) {
592                     d = uvchr_to_utf8(d, uv);
593                     puv = uv;
594                 }
595                 continue;
596             }
597             else if (uv == none) {      /* "none" is unmapped character */
598                 const int i = UTF8SKIP(s);
599                 Move(s, d, i, U8);
600                 d += i;
601                 s += i;
602                 puv = 0xfeedface;
603                 continue;
604             }
605             else if (uv == extra && !del) {
606                 matches++;
607                 if (havefinal) {
608                     s += UTF8SKIP(s);
609                     if (puv != final) {
610                         d = uvchr_to_utf8(d, final);
611                         puv = final;
612                     }
613                 }
614                 else {
615                     STRLEN len;
616                     uv = utf8n_to_uvchr(s, send - s, &len, UTF8_ALLOW_DEFAULT);
617                     if (uv != puv) {
618                         Move(s, d, len, U8);
619                         d += len;
620                         puv = uv;
621                     }
622                     s += len;
623                 }
624                 continue;
625             }
626             matches++;                  /* "none+1" is delete character */
627             s += UTF8SKIP(s);
628         }
629     }
630     else {
631         while (s < send) {
632             const UV uv = swash_fetch(rv, s, TRUE);
633             if (d > dend) {
634                 const STRLEN clen = d - dstart;
635                 const STRLEN nlen = dend - dstart + len + UTF8_MAXBYTES;
636                 if (!grows)
637                     Perl_croak(aTHX_ "panic: do_trans_complex_utf8 line %d",__LINE__);
638                 Renew(dstart, nlen + UTF8_MAXBYTES, U8);
639                 d = dstart + clen;
640                 dend = dstart + nlen;
641             }
642             if (uv < none) {
643                 matches++;
644                 s += UTF8SKIP(s);
645                 d = uvchr_to_utf8(d, uv);
646                 continue;
647             }
648             else if (uv == none) {      /* "none" is unmapped character */
649                 const int i = UTF8SKIP(s);
650                 Move(s, d, i, U8);
651                 d += i;
652                 s += i;
653                 continue;
654             }
655             else if (uv == extra && !del) {
656                 matches++;
657                 s += UTF8SKIP(s);
658                 d = uvchr_to_utf8(d, final);
659                 continue;
660             }
661             matches++;                  /* "none+1" is delete character */
662             s += UTF8SKIP(s);
663         }
664     }
665     if (grows || hibit) {
666         sv_setpvn(sv, (char*)dstart, d - dstart);
667         Safefree(dstart);
668         if (grows && hibit)
669             Safefree(start);
670     }
671     else {
672         *d = '\0';
673         SvCUR_set(sv, d - dstart);
674     }
675     SvUTF8_on(sv);
676     SvSETMAGIC(sv);
677
678     return matches;
679 }
680
681
682 /* Execute a tr//. sv is the value to be translated, while PL_op
683  * should be an OP_TRANS or OP_TRANSR op, whose op_pv field contains a
684  * translation table or whose op_sv field contains a swash.
685  * Returns a count of number of characters translated
686  */
687
688 I32
689 Perl_do_trans(pTHX_ SV *sv)
690 {
691     STRLEN len;
692     const I32 flags = PL_op->op_private;
693     const I32 hasutf = flags & (OPpTRANS_FROM_UTF | OPpTRANS_TO_UTF);
694
695     PERL_ARGS_ASSERT_DO_TRANS;
696
697     if (SvREADONLY(sv) && !(flags & OPpTRANS_IDENTICAL)) {
698         Perl_croak_no_modify();
699     }
700     (void)SvPV_const(sv, len);
701     if (!len)
702         return 0;
703     if (!(flags & OPpTRANS_IDENTICAL)) {
704         if (!SvPOKp(sv) || SvTHINKFIRST(sv))
705             (void)SvPV_force_nomg(sv, len);
706         (void)SvPOK_only_UTF8(sv);
707     }
708
709     /* If we use only OPpTRANS_IDENTICAL to bypass the READONLY check,
710      * we must also rely on it to choose the readonly strategy.
711      */
712     if (flags & OPpTRANS_IDENTICAL) {
713         return hasutf ? do_trans_count_utf8(sv) : do_trans_count(sv);
714     } else if (flags & (OPpTRANS_SQUASH|OPpTRANS_DELETE|OPpTRANS_COMPLEMENT)) {
715         return hasutf ? do_trans_complex_utf8(sv) : do_trans_complex(sv);
716     } else {
717         return hasutf ? do_trans_simple_utf8(sv) : do_trans_simple(sv);
718     }
719 }
720
721 void
722 Perl_do_join(pTHX_ SV *sv, SV *delim, SV **mark, SV **sp)
723 {
724     SV ** const oldmark = mark;
725     I32 items = sp - mark;
726     STRLEN len;
727     STRLEN delimlen;
728     const char * const delims = SvPV_const(delim, delimlen);
729
730     PERL_ARGS_ASSERT_DO_JOIN;
731
732     mark++;
733     len = (items > 0 ? (delimlen * (items - 1) ) : 0);
734     SvUPGRADE(sv, SVt_PV);
735     if (SvLEN(sv) < len + items) {      /* current length is way too short */
736         while (items-- > 0) {
737             if (*mark && !SvGAMAGIC(*mark) && SvOK(*mark)) {
738                 STRLEN tmplen;
739                 SvPV_const(*mark, tmplen);
740                 len += tmplen;
741             }
742             mark++;
743         }
744         SvGROW(sv, len + 1);            /* so try to pre-extend */
745
746         mark = oldmark;
747         items = sp - mark;
748         ++mark;
749     }
750
751     SvPVCLEAR(sv);
752     /* sv_setpv retains old UTF8ness [perl #24846] */
753     SvUTF8_off(sv);
754
755     if (TAINTING_get && SvMAGICAL(sv))
756         SvTAINTED_off(sv);
757
758     if (items-- > 0) {
759         if (*mark)
760             sv_catsv(sv, *mark);
761         mark++;
762     }
763
764     if (delimlen) {
765         const U32 delimflag = DO_UTF8(delim) ? SV_CATUTF8 : SV_CATBYTES;
766         for (; items > 0; items--,mark++) {
767             STRLEN len;
768             const char *s;
769             sv_catpvn_flags(sv,delims,delimlen,delimflag);
770             s = SvPV_const(*mark,len);
771             sv_catpvn_flags(sv,s,len,
772                             DO_UTF8(*mark) ? SV_CATUTF8 : SV_CATBYTES);
773         }
774     }
775     else {
776         for (; items > 0; items--,mark++)
777         {
778             STRLEN len;
779             const char *s = SvPV_const(*mark,len);
780             sv_catpvn_flags(sv,s,len,
781                             DO_UTF8(*mark) ? SV_CATUTF8 : SV_CATBYTES);
782         }
783     }
784     SvSETMAGIC(sv);
785 }
786
787 void
788 Perl_do_sprintf(pTHX_ SV *sv, SSize_t len, SV **sarg)
789 {
790     STRLEN patlen;
791     const char * const pat = SvPV_const(*sarg, patlen);
792     bool do_taint = FALSE;
793
794     PERL_ARGS_ASSERT_DO_SPRINTF;
795     assert(len >= 1);
796
797     if (SvTAINTED(*sarg))
798         TAINT_PROPER(
799                 (PL_op && PL_op->op_type < OP_max)
800                     ? (PL_op->op_type == OP_PRTF)
801                         ? "printf"
802                         : PL_op_name[PL_op->op_type]
803                     : "(unknown)"
804         );
805     SvUTF8_off(sv);
806     if (DO_UTF8(*sarg))
807         SvUTF8_on(sv);
808     sv_vsetpvfn(sv, pat, patlen, NULL, sarg + 1, (Size_t)(len - 1), &do_taint);
809     SvSETMAGIC(sv);
810     if (do_taint)
811         SvTAINTED_on(sv);
812 }
813
814 /* currently converts input to bytes if possible, but doesn't sweat failure */
815 UV
816 Perl_do_vecget(pTHX_ SV *sv, STRLEN offset, int size)
817 {
818     STRLEN srclen, len, avail, uoffset, bitoffs = 0;
819     const I32 svpv_flags = ((PL_op->op_flags & OPf_MOD || LVRET)
820                                           ? SV_UNDEF_RETURNS_NULL : 0);
821     unsigned char *s = (unsigned char *)
822                             SvPV_flags(sv, srclen, (svpv_flags|SV_GMAGIC));
823     UV retnum = 0;
824
825     if (!s) {
826       s = (unsigned char *)"";
827     }
828     
829     PERL_ARGS_ASSERT_DO_VECGET;
830
831     if (size < 1 || (size & (size-1))) /* size < 1 or not a power of two */
832         Perl_croak(aTHX_ "Illegal number of bits in vec");
833
834     if (SvUTF8(sv)) {
835         if (Perl_sv_utf8_downgrade(aTHX_ sv, TRUE)) {
836             /* PVX may have changed */
837             s = (unsigned char *) SvPV_flags(sv, srclen, svpv_flags);
838         }
839         else {
840             Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
841                                 "Use of strings with code points over 0xFF as"
842                                 " arguments to vec is deprecated. This will"
843                                 " be a fatal error in Perl 5.32");
844         }
845     }
846
847     if (size < 8) {
848         bitoffs = ((offset%8)*size)%8;
849         uoffset = offset/(8/size);
850     }
851     else if (size > 8) {
852         int n = size/8;
853         if (offset > Size_t_MAX / n - 1) /* would overflow */
854             return 0;
855         uoffset = offset*n;
856     }
857     else
858         uoffset = offset;
859
860     if (uoffset >= srclen)
861         return 0;
862
863     len   = (bitoffs + size + 7)/8; /* required number of bytes */
864     avail = srclen - uoffset;       /* available number of bytes */
865
866     /* Does the byte range overlap the end of the string? If so,
867      * handle specially. */
868     if (avail < len) {
869         if (size <= 8)
870             retnum = 0;
871         else {
872             if (size == 16) {
873                 assert(avail == 1);
874                 retnum = (UV) s[uoffset] <<  8;
875             }
876             else if (size == 32) {
877                 assert(avail >= 1 && avail <= 3);
878                 if (avail == 1)
879                     retnum =
880                         ((UV) s[uoffset    ] << 24);
881                 else if (avail == 2)
882                     retnum =
883                         ((UV) s[uoffset    ] << 24) +
884                         ((UV) s[uoffset + 1] << 16);
885                 else
886                     retnum =
887                         ((UV) s[uoffset    ] << 24) +
888                         ((UV) s[uoffset + 1] << 16) +
889                         (     s[uoffset + 2] <<  8);
890             }
891 #ifdef UV_IS_QUAD
892             else if (size == 64) {
893                 Perl_ck_warner(aTHX_ packWARN(WARN_PORTABLE),
894                                "Bit vector size > 32 non-portable");
895                 assert(avail >= 1 && avail <= 7);
896                 if (avail == 1)
897                     retnum =
898                         (UV) s[uoffset     ] << 56;
899                 else if (avail == 2)
900                     retnum =
901                         ((UV) s[uoffset    ] << 56) +
902                         ((UV) s[uoffset + 1] << 48);
903                 else if (avail == 3)
904                     retnum =
905                         ((UV) s[uoffset    ] << 56) +
906                         ((UV) s[uoffset + 1] << 48) +
907                         ((UV) s[uoffset + 2] << 40);
908                 else if (avail == 4)
909                     retnum =
910                         ((UV) s[uoffset    ] << 56) +
911                         ((UV) s[uoffset + 1] << 48) +
912                         ((UV) s[uoffset + 2] << 40) +
913                         ((UV) s[uoffset + 3] << 32);
914                 else if (avail == 5)
915                     retnum =
916                         ((UV) s[uoffset    ] << 56) +
917                         ((UV) s[uoffset + 1] << 48) +
918                         ((UV) s[uoffset + 2] << 40) +
919                         ((UV) s[uoffset + 3] << 32) +
920                         ((UV) s[uoffset + 4] << 24);
921                 else if (avail == 6)
922                     retnum =
923                         ((UV) s[uoffset    ] << 56) +
924                         ((UV) s[uoffset + 1] << 48) +
925                         ((UV) s[uoffset + 2] << 40) +
926                         ((UV) s[uoffset + 3] << 32) +
927                         ((UV) s[uoffset + 4] << 24) +
928                         ((UV) s[uoffset + 5] << 16);
929                 else
930                     retnum =
931                         ((UV) s[uoffset    ] << 56) +
932                         ((UV) s[uoffset + 1] << 48) +
933                         ((UV) s[uoffset + 2] << 40) +
934                         ((UV) s[uoffset + 3] << 32) +
935                         ((UV) s[uoffset + 4] << 24) +
936                         ((UV) s[uoffset + 5] << 16) +
937                         ((UV) s[uoffset + 6] <<  8);
938             }
939 #endif
940         }
941     }
942     else if (size < 8)
943         retnum = (s[uoffset] >> bitoffs) & ((1 << size) - 1);
944     else {
945         if (size == 8)
946             retnum = s[uoffset];
947         else if (size == 16)
948             retnum =
949                 ((UV) s[uoffset] <<      8) +
950                       s[uoffset + 1];
951         else if (size == 32)
952             retnum =
953                 ((UV) s[uoffset    ] << 24) +
954                 ((UV) s[uoffset + 1] << 16) +
955                 (     s[uoffset + 2] <<  8) +
956                       s[uoffset + 3];
957 #ifdef UV_IS_QUAD
958         else if (size == 64) {
959             Perl_ck_warner(aTHX_ packWARN(WARN_PORTABLE),
960                            "Bit vector size > 32 non-portable");
961             retnum =
962                 ((UV) s[uoffset    ] << 56) +
963                 ((UV) s[uoffset + 1] << 48) +
964                 ((UV) s[uoffset + 2] << 40) +
965                 ((UV) s[uoffset + 3] << 32) +
966                 ((UV) s[uoffset + 4] << 24) +
967                 ((UV) s[uoffset + 5] << 16) +
968                 (     s[uoffset + 6] <<  8) +
969                       s[uoffset + 7];
970         }
971 #endif
972     }
973
974     return retnum;
975 }
976
977 /* currently converts input to bytes if possible but doesn't sweat failures,
978  * although it does ensure that the string it clobbers is not marked as
979  * utf8-valid any more
980  */
981 void
982 Perl_do_vecset(pTHX_ SV *sv)
983 {
984     STRLEN offset, bitoffs = 0;
985     int size;
986     unsigned char *s;
987     UV lval;
988     I32 mask;
989     STRLEN targlen;
990     STRLEN len;
991     SV * const targ = LvTARG(sv);
992     char errflags = LvFLAGS(sv);
993
994     PERL_ARGS_ASSERT_DO_VECSET;
995
996     /* some out-of-range errors have been deferred if/until the LV is
997      * actually written to: f(vec($s,-1,8)) is not always fatal */
998     if (errflags) {
999         assert(!(errflags & ~(LVf_NEG_OFF|LVf_OUT_OF_RANGE)));
1000         if (errflags & LVf_NEG_OFF)
1001             Perl_croak_nocontext("Negative offset to vec in lvalue context");
1002         Perl_croak_nocontext("Out of memory!");
1003     }
1004
1005     if (!targ)
1006         return;
1007     s = (unsigned char*)SvPV_force_flags(targ, targlen,
1008                                          SV_GMAGIC | SV_UNDEF_RETURNS_NULL);
1009     if (SvUTF8(targ)) {
1010         /* This is handled by the SvPOK_only below...
1011         if (!Perl_sv_utf8_downgrade(aTHX_ targ, TRUE))
1012             SvUTF8_off(targ);
1013          */
1014         (void) Perl_sv_utf8_downgrade(aTHX_ targ, TRUE);
1015     }
1016
1017     (void)SvPOK_only(targ);
1018     lval = SvUV(sv);
1019     offset = LvTARGOFF(sv);
1020     size = LvTARGLEN(sv);
1021
1022     if (size < 1 || (size & (size-1))) /* size < 1 or not a power of two */
1023         Perl_croak(aTHX_ "Illegal number of bits in vec");
1024
1025     if (size < 8) {
1026         bitoffs = ((offset%8)*size)%8;
1027         offset /= 8/size;
1028     }
1029     else if (size > 8) {
1030         int n = size/8;
1031         if (offset > Size_t_MAX / n - 1) /* would overflow */
1032             Perl_croak_nocontext("Out of memory!");
1033         offset *= n;
1034     }
1035
1036     len = (bitoffs + size + 7)/8;       /* required number of bytes */
1037     if (targlen < offset || targlen - offset < len) {
1038         STRLEN newlen = offset > Size_t_MAX - len - 1 ? /* avoid overflow */
1039                                         Size_t_MAX : offset + len + 1;
1040         s = (unsigned char*)SvGROW(targ, newlen);
1041         (void)memzero((char *)(s + targlen), newlen - targlen);
1042         SvCUR_set(targ, newlen - 1);
1043     }
1044
1045     if (size < 8) {
1046         mask = (1 << size) - 1;
1047         lval &= mask;
1048         s[offset] &= ~(mask << bitoffs);
1049         s[offset] |= lval << bitoffs;
1050     }
1051     else {
1052         if (size == 8)
1053             s[offset  ] = (U8)( lval        & 0xff);
1054         else if (size == 16) {
1055             s[offset  ] = (U8)((lval >>  8) & 0xff);
1056             s[offset+1] = (U8)( lval        & 0xff);
1057         }
1058         else if (size == 32) {
1059             s[offset  ] = (U8)((lval >> 24) & 0xff);
1060             s[offset+1] = (U8)((lval >> 16) & 0xff);
1061             s[offset+2] = (U8)((lval >>  8) & 0xff);
1062             s[offset+3] = (U8)( lval        & 0xff);
1063         }
1064 #ifdef UV_IS_QUAD
1065         else if (size == 64) {
1066             Perl_ck_warner(aTHX_ packWARN(WARN_PORTABLE),
1067                            "Bit vector size > 32 non-portable");
1068             s[offset  ] = (U8)((lval >> 56) & 0xff);
1069             s[offset+1] = (U8)((lval >> 48) & 0xff);
1070             s[offset+2] = (U8)((lval >> 40) & 0xff);
1071             s[offset+3] = (U8)((lval >> 32) & 0xff);
1072             s[offset+4] = (U8)((lval >> 24) & 0xff);
1073             s[offset+5] = (U8)((lval >> 16) & 0xff);
1074             s[offset+6] = (U8)((lval >>  8) & 0xff);
1075             s[offset+7] = (U8)( lval        & 0xff);
1076         }
1077 #endif
1078     }
1079     SvSETMAGIC(targ);
1080 }
1081
1082 void
1083 Perl_do_vop(pTHX_ I32 optype, SV *sv, SV *left, SV *right)
1084 {
1085 #ifdef LIBERAL
1086     long *dl;
1087     long *ll;
1088     long *rl;
1089 #endif
1090     char *dc;
1091     STRLEN leftlen;
1092     STRLEN rightlen;
1093     const char *lc;
1094     const char *rc;
1095     STRLEN len;
1096     STRLEN lensave;
1097     const char *lsave;
1098     const char *rsave;
1099     STRLEN needlen = 0;
1100     bool result_needs_to_be_utf8 = FALSE;
1101     bool left_utf8 = FALSE;
1102     bool right_utf8 = FALSE;
1103     U8 * left_non_downgraded = NULL;
1104     U8 * right_non_downgraded = NULL;
1105     Size_t left_non_downgraded_len = 0;
1106     Size_t right_non_downgraded_len = 0;
1107     char * non_downgraded = NULL;
1108     Size_t non_downgraded_len = 0;
1109
1110     PERL_ARGS_ASSERT_DO_VOP;
1111
1112     if (sv != left || (optype != OP_BIT_AND && !SvOK(sv)))
1113         SvPVCLEAR(sv);        /* avoid undef warning on |= and ^= */
1114     if (sv == left) {
1115         lc = SvPV_force_nomg(left, leftlen);
1116     }
1117     else {
1118         lc = SvPV_nomg_const(left, leftlen);
1119         SvPV_force_nomg_nolen(sv);
1120     }
1121     rc = SvPV_nomg_const(right, rightlen);
1122
1123     /* This needs to come after SvPV to ensure that string overloading has
1124        fired off.  */
1125
1126     /* Create downgraded temporaries of any UTF-8 encoded operands */
1127     if (DO_UTF8(left)) {
1128         const U8 * save_lc = (U8 *) lc;
1129
1130         left_utf8 = TRUE;
1131         result_needs_to_be_utf8 = TRUE;
1132
1133         left_non_downgraded_len = leftlen;
1134         lc = (char *) bytes_from_utf8_loc((const U8 *) lc, &leftlen,
1135                                           &left_utf8,
1136                                           (const U8 **) &left_non_downgraded);
1137         /* Calculate the number of trailing unconvertible bytes.  This quantity
1138          * is the original length minus the length of the converted portion. */
1139         left_non_downgraded_len -= left_non_downgraded - save_lc;
1140         SAVEFREEPV(lc);
1141     }
1142     if (DO_UTF8(right)) {
1143         const U8 * save_rc = (U8 *) rc;
1144
1145         right_utf8 = TRUE;
1146         result_needs_to_be_utf8 = TRUE;
1147
1148         right_non_downgraded_len = rightlen;
1149         rc = (char *) bytes_from_utf8_loc((const U8 *) rc, &rightlen,
1150                                           &right_utf8,
1151                                           (const U8 **) &right_non_downgraded);
1152         right_non_downgraded_len -= right_non_downgraded - save_rc;
1153         SAVEFREEPV(rc);
1154     }
1155
1156     /* We set 'len' to the length that the operation actually operates on.  The
1157      * dangling part of the longer operand doesn't actually participate in the
1158      * operation.  What happens is that we pretend that the shorter operand has
1159      * been extended to the right by enough imaginary zeros to match the length
1160      * of the longer one.  But we know in advance the result of the operation
1161      * on zeros without having to do it.  In the case of '&', the result is
1162      * zero, and the dangling portion is simply discarded.  For '|' and '^', the
1163      * result is the same as the other operand, so the dangling part is just
1164      * appended to the final result, unchanged.  We currently accept above-FF
1165      * code points in the dangling portion, as that's how it has long worked,
1166      * and code depends on it staying that way.  But it is now fatal for
1167      * above-FF to appear in the portion that does get operated on.  Hence, any
1168      * above-FF must come only in the longer operand, and only in its dangling
1169      * portion.  That means that at least one of the operands has to be
1170      * entirely non-UTF-8, and the length of that operand has to be before the
1171      * first above-FF in the other */
1172     if (left_utf8) {
1173         if (right_utf8 || rightlen > leftlen) {
1174             Perl_croak(aTHX_ fatal_above_ff_msg, PL_op_desc[optype]);
1175         }
1176         len = rightlen;
1177     }
1178     else if (right_utf8) {
1179         if (leftlen > rightlen) {
1180             Perl_croak(aTHX_ fatal_above_ff_msg, PL_op_desc[optype]);
1181         }
1182         len = leftlen;
1183     }
1184     else {  /* Neither is UTF-8 */
1185         len = leftlen < rightlen ? leftlen : rightlen;
1186     }
1187
1188     lensave = len;
1189     lsave = lc;
1190     rsave = rc;
1191
1192     SvCUR_set(sv, len);
1193     (void)SvPOK_only(sv);
1194     if (SvOK(sv) || SvTYPE(sv) > SVt_PVMG) {
1195         dc = SvPV_force_nomg_nolen(sv);
1196         if (SvLEN(sv) < len + 1) {
1197             dc = SvGROW(sv, len + 1);
1198             (void)memzero(dc + SvCUR(sv), len - SvCUR(sv) + 1);
1199         }
1200     }
1201     else {
1202         needlen = optype == OP_BIT_AND
1203                     ? len : (leftlen > rightlen ? leftlen : rightlen);
1204         Newxz(dc, needlen + 1, char);
1205         sv_usepvn_flags(sv, dc, needlen, SV_HAS_TRAILING_NUL);
1206         dc = SvPVX(sv);         /* sv_usepvn() calls Renew() */
1207     }
1208
1209 #ifdef LIBERAL
1210     if (len >= sizeof(long)*4 &&
1211         !((unsigned long)dc % sizeof(long)) &&
1212         !((unsigned long)lc % sizeof(long)) &&
1213         !((unsigned long)rc % sizeof(long)))    /* It's almost always aligned... */
1214     {
1215         const STRLEN remainder = len % (sizeof(long)*4);
1216         len /= (sizeof(long)*4);
1217
1218         dl = (long*)dc;
1219         ll = (long*)lc;
1220         rl = (long*)rc;
1221
1222         switch (optype) {
1223         case OP_BIT_AND:
1224             while (len--) {
1225                 *dl++ = *ll++ & *rl++;
1226                 *dl++ = *ll++ & *rl++;
1227                 *dl++ = *ll++ & *rl++;
1228                 *dl++ = *ll++ & *rl++;
1229             }
1230             break;
1231         case OP_BIT_XOR:
1232             while (len--) {
1233                 *dl++ = *ll++ ^ *rl++;
1234                 *dl++ = *ll++ ^ *rl++;
1235                 *dl++ = *ll++ ^ *rl++;
1236                 *dl++ = *ll++ ^ *rl++;
1237             }
1238             break;
1239         case OP_BIT_OR:
1240             while (len--) {
1241                 *dl++ = *ll++ | *rl++;
1242                 *dl++ = *ll++ | *rl++;
1243                 *dl++ = *ll++ | *rl++;
1244                 *dl++ = *ll++ | *rl++;
1245             }
1246         }
1247
1248         dc = (char*)dl;
1249         lc = (char*)ll;
1250         rc = (char*)rl;
1251
1252         len = remainder;
1253     }
1254 #endif
1255     switch (optype) {
1256     case OP_BIT_AND:
1257         while (len--)
1258             *dc++ = *lc++ & *rc++;
1259         *dc = '\0';
1260         break;
1261     case OP_BIT_XOR:
1262         while (len--)
1263             *dc++ = *lc++ ^ *rc++;
1264         goto mop_up;
1265     case OP_BIT_OR:
1266         while (len--)
1267             *dc++ = *lc++ | *rc++;
1268       mop_up:
1269         len = lensave;
1270         if (rightlen > len) {
1271             if (dc == rc)
1272                 SvCUR(sv) = rightlen;
1273             else
1274                 sv_catpvn_nomg(sv, rsave + len, rightlen - len);
1275         }
1276         else if (leftlen > len) {
1277             if (dc == lc)
1278                 SvCUR(sv) = leftlen;
1279             else
1280                 sv_catpvn_nomg(sv, lsave + len, leftlen - len);
1281         }
1282         *SvEND(sv) = '\0';
1283
1284         /* If there is trailing stuff that couldn't be converted from UTF-8, it
1285          * is appended as-is for the ^ and | operators.  This preserves
1286          * backwards compatibility */
1287         if (right_non_downgraded) {
1288             non_downgraded = (char *) right_non_downgraded;
1289             non_downgraded_len = right_non_downgraded_len;
1290         }
1291         else if (left_non_downgraded) {
1292             non_downgraded = (char *) left_non_downgraded;
1293             non_downgraded_len = left_non_downgraded_len;
1294         }
1295
1296         break;
1297     }
1298
1299     if (result_needs_to_be_utf8) {
1300         sv_utf8_upgrade_nomg(sv);
1301
1302         /* Append any trailing UTF-8 as-is. */
1303         if (non_downgraded) {
1304             sv_catpvn_nomg(sv, non_downgraded, non_downgraded_len);
1305         }
1306     }
1307
1308     SvTAINT(sv);
1309 }
1310
1311
1312 /* Perl_do_kv() may be:
1313  *  * called directly as the pp function for pp_keys() and pp_values();
1314  *  * It may also be called directly when the op is OP_AVHVSWITCH, to
1315  *       implement CORE::keys(), CORE::values().
1316  *
1317  * In all cases it expects an HV on the stack and returns a list of keys,
1318  * values, or key-value pairs, depending on PL_op.
1319  */
1320
1321 OP *
1322 Perl_do_kv(pTHX)
1323 {
1324     dSP;
1325     HV * const keys = MUTABLE_HV(POPs);
1326     const U8 gimme = GIMME_V;
1327
1328     const I32 dokeys   =     (PL_op->op_type == OP_KEYS)
1329                           || (    PL_op->op_type == OP_AVHVSWITCH
1330                               && (PL_op->op_private & OPpAVHVSWITCH_MASK)
1331                                     + OP_EACH == OP_KEYS);
1332
1333     const I32 dovalues =     (PL_op->op_type == OP_VALUES)
1334                           || (    PL_op->op_type == OP_AVHVSWITCH
1335                               && (PL_op->op_private & OPpAVHVSWITCH_MASK)
1336                                      + OP_EACH == OP_VALUES);
1337
1338     assert(   PL_op->op_type == OP_KEYS
1339            || PL_op->op_type == OP_VALUES
1340            || PL_op->op_type == OP_AVHVSWITCH);
1341
1342     assert(!(    PL_op->op_type == OP_VALUES
1343              && (PL_op->op_private & OPpMAYBE_LVSUB)));
1344
1345     (void)hv_iterinit(keys);    /* always reset iterator regardless */
1346
1347     if (gimme == G_VOID)
1348         RETURN;
1349
1350     if (gimme == G_SCALAR) {
1351         if (PL_op->op_flags & OPf_MOD || LVRET) {       /* lvalue */
1352             SV * const ret = sv_2mortal(newSV_type(SVt_PVLV));  /* Not TARG RT#67838 */
1353             sv_magic(ret, NULL, PERL_MAGIC_nkeys, NULL, 0);
1354             LvTYPE(ret) = 'k';
1355             LvTARG(ret) = SvREFCNT_inc_simple(keys);
1356             PUSHs(ret);
1357         }
1358         else {
1359             IV i;
1360             dTARGET;
1361
1362             /* note that in 'scalar(keys %h)' the OP_KEYS is usually
1363              * optimised away and the action is performed directly by the
1364              * padhv or rv2hv op. We now only get here via OP_AVHVSWITCH
1365              * and \&CORE::keys
1366              */
1367             if (! SvTIED_mg((const SV *)keys, PERL_MAGIC_tied) ) {
1368                 i = HvUSEDKEYS(keys);
1369             }
1370             else {
1371                 i = 0;
1372                 while (hv_iternext(keys)) i++;
1373             }
1374             PUSHi( i );
1375         }
1376         RETURN;
1377     }
1378
1379     if (UNLIKELY(PL_op->op_private & OPpMAYBE_LVSUB)) {
1380         const I32 flags = is_lvalue_sub();
1381         if (flags && !(flags & OPpENTERSUB_INARGS))
1382             /* diag_listed_as: Can't modify %s in %s */
1383             Perl_croak(aTHX_ "Can't modify keys in list assignment");
1384     }
1385
1386     PUTBACK;
1387     hv_pushkv(keys, (dokeys | (dovalues << 1)));
1388     return NORMAL;
1389 }
1390
1391 /*
1392  * ex: set ts=8 sts=4 sw=4 et:
1393  */